剑指 Offer 58 - I. 翻转单词顺序

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。

 

示例 1:

输入: "the sky is blue"
输出: "blue is sky the"
示例 2:

输入: "  hello world!  "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:

输入: "a good   example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
 

说明:

无空格字符构成一个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
注意:本题与主站 151 题相同:https://leetcode-cn.com/problems/reverse-words-in-a-string/

注意:此题对比原题有改动

 

 

 

解法1:

笨蛋解法——先另外写一个去空格函数去掉string首尾的空格,再从头开始用循环每次截取第一个单词进栈,保存截剩下的字符串并再次去除首尾空格(防止单词与单词间有多个空格),之后再从剩下的字符串截取单词,如此循环往复直至最后。

循环结束后,栈中所有单词出栈并以空格拼接起来即是题目所要求的顺序。

复制代码
class Solution {
public:
    string reverseWords(string s) {
        trim(s);
        if(s.empty())        //特殊情况
            return s;
        stack<string> S;
        int n = s.find(' ');
        string piece = s.substr(0,n), remain = s.substr(n+1);
        if(remain.at(0) == ' ')  //去首尾空格
            trim(remain);
        while(n != string::npos) //截取单词
        {
            S.push(piece);
            // cout<<"S.top:"<<S.top()<<"\tremain:"<<remain<<endl;
            if(remain.at(0) == ' ')
                trim(remain);
            n = remain.find(' ');
            piece = remain.substr(0,n);
            remain = remain.substr(n+1);
            
        }
        S.push(remain);     //找不到空格了,直接入栈
        s.clear();        //原字符串清空
        while(!S.empty())    //出栈,拼接单词
        {
            bool last_empty = false;
            s.append(S.top());
            s.append(" ");
            S.pop();
        }
        while(s.at(s.size() - 1) == ' ')
            s.pop_back();
        return s;
    }


     void trim(string &s)      //去字符串首尾空格
    {
      if( !s.empty() )      
      {
          s.erase(0,s.find_first_not_of(" "));
          s.erase(s.find_last_not_of(" ") + 1);
      }
    }
  
};
复制代码

此算法未经深思熟虑,时空复杂度均表现不佳,尤其空间复杂度是其他算法的8-10倍。

 

解法2:

从后向前遍历,用俩索引i,j标出单词并拼接。

复制代码
 1 class Solution {
 2 public:
 3     string reverseWords(string s) {
 4         if (s.empty())
 5             return s;
 6         string res = "";
 7         int i = s.size() - 1;           //i从字符串最后开始
 8         while (i >= 0){
 9             while (i >= 0 && s.at(i) == ' ')  
10                 --i;
11             int j = i;               //j为当前指向单词的最后一个字母
12             while (i >= 0 && s.at(i) != ' '){
13                 --i;      
14             }                    //i为当前指向单词前的第一个空格
15             if (i < j){              //只要还有单词
16                 res += s.substr(i + 1, j - i);//就拼接
17                 res += " ";
18             }
19         }
20         return res.substr(0, res.size() - 1); //去最后的空格
21     }
22 
23 
24 };
复制代码

空间占用相比上个算法大大改善,时间上若是可以把字符串拼接中的+改为string类的方法append会更快。

 

方法3:

与算法1想法类似,但空间占用大大改善。

复制代码
 1 class Solution {
 2 public:
 3     string reverseWords(string s) {
 4        stack<string>sta;//利用栈实现倒装string  以空格为界限分割每个单词 每个单词作为stack的元素压栈
 5        int len = s.size();
 6        for(int i = 0;i < len;++i)
 7        {
 8            string s1;//一个单词  单词以空格分割
 9            while(i < len && !isblank(s[i]))
10            {
11               s1 += s[i];
12               ++i;
13            }
14            if(!s1.empty())
15                sta.push(s1);
16        }
17        string s2 = "";
18        while(!sta.empty())
19        {
20            s2 += sta.top();
21            sta.pop();
22            if(!sta.empty())
23                s2 += " ";
24        }
25        return s2;
26     }
27 };
复制代码

 

方法4:

换python一行解决。

1 class Solution:
2     def reverseWords(self, s: str) -> str:
3         return " ".join(s.split()[::-1])

然而看着虽然爽,时间占用上是算法1的5倍,空间占用上是算法2、3的2倍。

 

方法5:

利用istream类去空格的特性,借助栈完成目标。

复制代码
 1 class Solution {
 2 public:
 3     string reverseWords(string s) {
 4         stack<string> stack1;
 5         istringstream input(s);
 6         string t;
 7         string res;
 8         while(input>>t)stack1.push(t);//每遇到一个空格就循环一次直到结尾
 9         while(!stack1.empty()){    
10             res.append(stack1.top());
11             res.append(" ");
12             stack1.pop();
13         }
14         if(res.length()==0)return res;
15         res.pop_back();        //去最后的空格
16         return res;
17     }
18 };
复制代码

此法在时间空间复杂度均一般,时间复杂度与算法1、2、3持平,空间复杂度与算法2、3持平。

 

方法6:

复制代码
 1 class Solution {
 2 public:
 3     string reverseWords(string s) {
 4         stack<char> word;
 5         string result = "";
 6         for (int i = s.size() - 1; i >= 0; --i)
 7         {
 8             if (s[i] != ' ') //遇到单词则入栈
 9             {
10                 word.push(s[i]);
11             }
12             if (s[i] == ' ' || i == 0) //遇到空格或第一个字符都要检查一下栈中是否有单词可以弹出
13             {
14                 bool flag = false; //标记是否发生出栈
15                 while (word.empty() == false)
16                 {
17                     result.push_back(word.top()); //因为word栈存储的元素为char型,而result为string型,故不能相加,只能使用push_back()
18                     word.pop();
19                     flag = true;
20                 }
21                 if (flag)
22                 {
23                     result += " ";
24                 }
25             }
26         }
27         return result.substr(0, result.size() - 1); //最后一个单词后面会多加一个空格
28     }
29 };
30 
31 // 作者:wade-d
32 // 链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/solution/151-fan-zhuan-zi-fu-chuan-li-de-dan-ci-y-hn6y/
33 // 来源:力扣(LeetCode)
34 // 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复制代码

用字母栈,从后向前遍历,遇字母则入,遇空格全部弹出,至开头全部弹出。
此法用时与内存消耗方面均表现优异。

posted @   Jasmine_Sokko  阅读(52)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示