Problem overview
ReverseWords receives a string input of words separated by single spaces and returns the words in reverse order, joined by single spaces. For "sky is blue" the result is "blue is sky". A word is a run of non-space characters, and the statement guarantees exactly one space between neighbouring words.
Approach
A direct solution splits the string into words, reverses that list and joins it back. This lesson does it with swaps on a character array, in two passes of the same helper:
- Reverse the whole string. The words are now in the opposite order, but each one is spelled backwards.
- Reverse each word on its own, so it is spelled correctly again.
For "sky is blue", the first pass produces "eulb si yks". The second pass finds the words eulb, si and yks and reverses each, giving "blue is sky". Because the spaces are single and sit between words, they land in the right places after the first reversal and are never moved again.
Both passes use one helper, Reverse(arr, i, j), which reverses the part of the array from index i to index j inclusive. That helper in turn uses Swap(arr, i, j). Strings are immutable in C#, which is why the work happens on a char[] copy.
Following the word loop
After the first reversal the array holds "eulb si yks", which has 11 characters. The loop starts with i = 0. The inner loop moves j forward until it finds the space at index 4, so the word is indexes 0 to 3, and Reverse(arr, 0, 3) turns eulb into blue. Then i becomes 5. The next word, si, occupies indexes 5 and 6, and the space is at index 7. The last word starts at index 8. There j stops because it reached 11, the array's length, not because of a space, and Reverse(arr, 8, 10) fixes yks. Then i becomes 12 and the outer loop ends.
This is why the loop condition on j checks the length as well as the space: the last word has no space after it.
Step by step
- Copy the characters into
arrwithinput.ToCharArray(), a new array that can be changed. - Reverse everything by calling
Reverse(arr, 0, arr.Length - 1). - Track the current word's start in
i, beginning at 0. - Loop while
i < arr.Length, one iteration per word. - Find the word's end. Start
jatiand advance it whilej < arr.Lengthandarr[j]isn't a space. Check the length first:&&stops at the first false side, soarr[j]is never read past the end. - Reverse the word. It spans
itoj - 1, becausejis the space after it or the end of the array. - Skip the space by setting
itoj + 1. - Return
new string(arr)after the loop. - Write
Reverse. Whilei < j, callSwap(arr, i, j), then moveiup andjdown. Both parameters are copies, so changing them doesn't affect the caller's variables. - Write
Swap. Savearr[i]intemp, copyarr[j]intoarr[i], then puttempintoarr[j].
The solution in C#
class Solution {
public void Swap(char[] arr, int i, int j) {
char temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public void Reverse(char[] arr, int i, int j) {
while (i < j) {
Swap(arr, i, j);
i++;
j--;
}
}
public string ReverseWords(string input) {
char[] arr = input.ToCharArray();
Reverse(arr, 0, arr.Length - 1);
int i = 0;
while (i < arr.Length) {
int j = i;
while (j < arr.Length && arr[j] != ' ') {
j++;
}
Reverse(arr, i, j - 1);
i = j + 1;
}
return new string(arr);
}
}
C# details:
- Arrays are reference types.
ReverseandSwapreturnvoid, yet the caller sees the changes, because they receive a reference to the same array. The integersiandjare passed by value, so the loop insideReversedoesn't alter the caller's owniandj. - Char literals use single quotes.
' 'is one space character. A string literal" "would not compare with acharusing!=. - A method named
Reverseis fine, since it is a member ofSolution. Inside the class, the callReverse(arr, ...)resolves to it. - The final conversion.
new string(arr)builds a string from all the characters in the array. The originalinputis unchanged.
Complexity
Time: O(n). The whole-string reversal touches each character once. The word loop moves j across every character once in total, and reversing the words touches each of those characters once more. Altogether it is a few linear passes.
Space: O(n). The character array is a copy of the input. The swaps themselves use constant extra memory, so the array is the only linear cost.
Edge cases and common mistakes
- A single word.
"hi"is reversed to"ih"and the word pass restores"hi". - The empty string.
Reverse(arr, 0, -1)does nothing because0 < -1is false, and the word loop never runs. The result is an empty string. - Checking
arr[j]beforej < arr.Length. At the last wordjreaches the length, and the read throwsIndexOutOfRangeException. - Reversing
itojinstead ofitoj - 1. That includes the space after the word in the swap and moves it into the word's first position. - Extra spaces. The statement promises single spaces. If the input had leading, trailing or repeated spaces, this code would keep them, mirrored in position, instead of collapsing them. For
" a"it returns"a ". - Skipping the second pass. The whole-string reversal alone gives
"eulb si yks". Each word needs its own reversal.
Testing
"sky is blue"gives"blue is sky"."a b"gives"b a"."hi"gives"hi".""gives"".