4, String: flip the words in the string

Posted by BostonMark on Wed, 15 Dec 2021 06:06:42 +0100

https://leetcode-cn.com/problems/reverse-words-in-a-string/

Given a string, flip each word in the string one by one.

Example 1:
Input: "the sky is blue"
Output: "blue is sky the"

Example 2:
Enter: "hello world!  "
Output: "world! hello"
Explanation: the input string can contain extra spaces before or after, but the inverted characters cannot be included.

Example 3:
Enter: "a good example"
Output: "example good a"
Explanation: if there is extra space between two words, reduce the space between words after inversion to only one.

1, Train of thought

This topic can be said to comprehensively investigate a variety of string operations.

Some students will use the split library function to separate words, then define a new string, and finally add the words in reverse order. Then this problem is a water problem and loses its meaning. So here I still improve the difficulty of this problem: do not use auxiliary space, and the space complexity is required to be O(1). If you can't use auxiliary space, you can only work on the original string. Think about it. If we reverse the whole string, the order of the words is specified to be reverse, but the words themselves are also flashed. Then reverse the words, and the words will not come right.

Therefore, the solution is as follows:

  • Remove extra spaces
  • Invert the entire string
  • Invert each word

For example, the source string is: "the sky is blue"

  • Remove extra spaces: "the sky is blue"
  • String inversion: "eulb si yks eht"
  • Word reversal: "blue is sky the"

In this way, we have finished flipping the words in the string. The idea is very clear. Let's talk about the implementation details of the code. Take the removal of redundant spaces as an example. Some students will write the following code:

void removeExtraSpaces(string& s) {
    for (int i = s.size() - 1; i > 0; i--) {
        if (s[i] == s[i - 1] && s[i] == ' ') {
            s.erase(s.begin() + i);
        }
    }
    // Deletes the last space in the string
    if (s.size() > 0 && s[s.size() - 1] == ' ') {
        s.erase(s.begin() + s.size() - 1);
    }
    // Delete the first space in the string
    if (s.size() > 0 && s[0] == ' ') {
        s.erase(s.begin());
    }
}

The logic is very simple. Traverse from front to back. Erase when you encounter a space. If you don't think about the time complexity of erase, you think the above code is O(n) time complexity. Think about the real time complexity. An erase is an O(n) operation. The implementation principle of erase is as follows: Array: is it difficult to remove just one element?  (opens new window) , the optimal algorithm to remove elements also needs O(n). The erase operation also sets a for loop, so the code time complexity of removing redundant spaces in the above code is O(n^2).

Then use the double finger needle method to remove the spaces, and finally resize the size of the string to achieve the time complexity of O(n). If you are unfamiliar with this operation, you can take another look at this article: Array: is it difficult to remove just one element?  (opens new window) How elements are removed.

Then use double pointers to remove redundant spaces. The code is as follows: fastIndex goes fast and slowIndex goes slow. Finally, slowIndex marks the length of the new string after removing redundant spaces.

void removeExtraSpaces(string& s) {
    int slowIndex = 0, fastIndex = 0; // Define fast pointer, slow pointer
    // Remove the space before the string
    while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
        fastIndex++;
    }
    for (; fastIndex < s.size(); fastIndex++) {
        // Remove redundant spaces in the middle of the string
        if (fastIndex - 1 > 0
                && s[fastIndex - 1] == s[fastIndex]
                && s[fastIndex] == ' ') {
            continue;
        } else {
            s[slowIndex++] = s[fastIndex];
        }
    }
    if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // Remove the space at the end of the string
        s.resize(slowIndex - 1);
    } else {
        s.resize(slowIndex); // Reset string size
    }
}

Some students may find that erase is used to remove spaces, and the performance on leetcode is also OK. The main points are as follows:

  1. In the test set on leetcode, the length of the string is not long enough. If it is long enough, the performance gap will be very obvious.
  2. leetcode's test program is not very accurate.

At this point, we have implemented the removeExtraSpaces function to remove redundant spaces.

It also implements the function of reversing the string, and supports the inversion of the string sub interval. We implement this in 344. Reverse string (opens new window) and 541. Reverse string II (opens new window) It's already said in.

The code is as follows:

// Invert the left closed and closed interval in string s [start, end]
void reverse(string& s, int start, int end) {
    for (int i = start, j = end; i < j; i++, j--) {
        swap(s[i], s[j]);
    }
}

C + + overall code

// Version one
class Solution {
public:
    // Invert the left closed and closed interval in string s [start, end]
    void reverse(string& s, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            swap(s[i], s[j]);
        }
    }

    // Remove redundant spaces: algorithm using double pointer (fast and slow pointer method) O(n)
    void removeExtraSpaces(string& s) {
        int slowIndex = 0, fastIndex = 0; // Define fast pointer, slow pointer
        // Remove the space before the string
        while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
            fastIndex++;
        }
        for (; fastIndex < s.size(); fastIndex++) {
            // Remove redundant spaces in the middle of the string
            if (fastIndex - 1 > 0
                    && s[fastIndex - 1] == s[fastIndex]
                    && s[fastIndex] == ' ') {
                continue;
            } else {
                s[slowIndex++] = s[fastIndex];
            }
        }
        if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // Remove the space at the end of the string
            s.resize(slowIndex - 1);
        } else {
            s.resize(slowIndex); // Reset string size
        }
    }

    string reverseWords(string s) {
        removeExtraSpaces(s); // Remove redundant spaces
        reverse(s, 0, s.size() - 1); // Invert all strings
        int start = 0; // The starting position of the inverted word in the string
        int end = 0; // The ending position of the inverted word in the string
        bool entry = false; // Marks whether a word interval has been entered during the enumeration of strings
        for (int i = 0; i < s.size(); i++) { // Start reversing words
            if (!entry) {
                start = i; // Determine the starting position of the word
                entry = true; // Enter word interval
            }
            // When there is a space after a word, the space is the word breaker
            if (entry && s[i] == ' ' && s[i - 1] != ' ') {
                end = i - 1; // Determine where the word ends
                entry = false; // End word interval
                reverse(s, start, end);
            }
            // There is no space after the last ending word
            if (entry && (i == (s.size() - 1)) && s[i] != ' ' ) {
                end = i;// Determine where the word ends
                entry = false; // End word interval
                reverse(s, start, end);
            }
        }
        return s;
    }
    
    // Of course, the main function reverseWords here has some redundancy, which can be simplified. After simplification, the main function is:
    /* Simple writing of main function
    string reverseWords(string s) {
        removeExtraSpaces(s);
        reverse(s, 0, s.size() - 1);
        for(int i = 0; i < s.size(); i++) {
            int j = i;
            // Find the space between words and flip the words
            while(j < s.size() && s[j] != ' ') j++;
            reverse(s, i, j - 1);
            i = j;
        }
        return s;
    }
    */
};

Topics: leetcode