Code Top -- 14 颠倒字符串中的单词

原地O(1),整体和单词两次翻转

Posted by OUC_LiuX on April 19, 2022

from CodeTop, Leetcode, 151. 颠倒字符串中的单词
两次翻转,这尼玛就不是人能想出来的。

题意:

示例 1:
输入:s = “the sky is blue”
输出:”blue is sky the”

示例 2:
输入:s = “  hello world  ”
输出:”world hello”
解释:颠倒后的字符串中不能存在前导空格和尾随空格。

示例 3:
输入:s = “a good   example”
输出:”example good a”
解释:如果两个单词间有多余的空格,颠倒后的字符串需要将单词间的空格减少到仅有一个。

解读:
将不含空格的 单词 按顺序 从前往后加入到字符串,并且人工添加以空格区分。添加的同时反转单词。
而所有单词翻转并添加完毕,翻转整个字符串。
注意:

  1. 只有存在单词的时候,才在后面人工添加空格。
  2. 如果有单词,最后添加的空格属于无效空格,要去掉。
  3. 可以在重新添加完单词后,删除掉字符串尾部无效的字符。

代码:

int i = 0, k = 0;   // k 充当重新添加单词的位置指针    
while(i < s.size()){
    while(i < s.size() && s[i] == ' ') i++; // 找到第一个非空格字符       
    if (i == s.size()) break;   // 代表着后面没有单词,全是空格,直接退出       

    int j = i + 1;  // 充当单词终点指针            
    while(j < s.size() && s[j] != ' ') j++;
    reverse(s.begin() + i, s.begin() + j);  // 单词自身翻转        
    while(i < j)    s[k++] = s[i++];    // 自前向后顺序添加单词,人工过滤空格        
    s[k++] = ' ';    // 在新添加的单词后面加一个空格          
}

if (k) k--; // k 存在,证明有单词,则最后加入的一个单词后面一定有一个多余的空格。        

s.erase(s.begin()+k, s.end()); // 有效的单词全在 k 前面,后面属于无效字符,删去。       

reverse(s.begin(), s.end());    
// 单词逐个翻转后,整体再翻转一遍,实现单词郑正序,句子倒序。              

return s;