Problem

Given a string and a set of delimiters, reverse the words in the string while maintaining the relative order of the delimiters. For example, given “hello/world:here”, return “here/world:hello”

Follow-up

Does your solution work for the following cases: "hello/world:here/", "hello//world:here"

Examples

Example 1:

Input: s = hello/world:here
Output: here/world:hello

Solution

Method 1 - Using stack to store words and queue for delimiters

Code

Java
class Solution {

	public String reverseWords(String s) {
		Stack<String> stack = new Stack<>();
		Queue<String> queue = new LinkedList<>();

		StringBuilder word = new StringBuilder();
		int i = 0;

		while (i < s.length()) {
			char c = s.charAt(i);

			if (Character.isLetterOrDigit(c)) {
				word.append(c);
				i++;
			} else {
				if (word.length() > 0) {
					stack.push(word.toString());
				}

				word = new StringBuilder(); // clear word for next word
				StringBuilder delim = new StringBuilder();
				delim.append(c);
				i++;
				// tracking continuous delimiter to add to queue
				while (i < s.length() && !Character.isLetterOrDigit(s.charAt(i))) {
					delim.append(c);
					i++;
				}

				queue.add(delim.toString());
			}
		}

		// if string ends with words
		if (word.length() != 0) {
			stack.push(word.toString());
		}

		boolean isWordFirst = Character.isLetterOrDigit(s.charAt(0));
		StringBuilder sb = new StringBuilder();

		// if word is not first, add 1 entry from queue
		if (!isWordFirst) {
			if (!queue.isEmpty()) {
				sb.append(queue.remove());
			}
		}
		// now put 1 element from either till not empty
		while (!stack.isEmpty() || !queue.isEmpty()) {
			if (!stack.isEmpty()) {
				sb.append(stack.pop());
			}

			if (!queue.isEmpty()) {
				sb.append(queue.remove());
			}
		}

		return sb.toString();
	}
}

Complexity

  • ⏰ Time complexity: O(n)
  • 🧺 Space complexity: O(n)