剑指 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 // 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
用字母栈,从后向前遍历,遇字母则入,遇空格全部弹出,至开头全部弹出。
此法用时与内存消耗方面均表现优异。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了