题意
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。
解法1—双指针
算法解析
- 去除字符串前后空格
- 倒序遍历字符串 s ,记录单词左右索引边界 i , j ;
- 每确定一个单词的边界,则将其添加至单词列表 res ;
- 最终,将单词列表拼接为字符串,并返回即可。
复杂度分析:
- 时间复杂度 O(N): 其中 N 为字符串 s 的长度,线性遍历字符串。
-
空间复杂度 O(N) : 新建的string(C++)中的字符串总长度≤N ,占用 O(N) 大小的额外空间。
C++实现
class Solution
{
public:
string reverseWords(string s)
{
string res;
for(int j=s.size()-1;j>=0;--j)
{
//从后往前寻找第一个单词的右边界
if(s[j]==' ')
continue;
int i=j; // i初始化为单词的右边界
while( i>=0 && s[i]!=' ' ) //寻找i真正的位置
i--;
res.append(s.substr(i+1,j-i));
res.append(" ");
j=i;
}
if (!res.empty())
{
res.pop_back(); //删除最后一个空格
}
return res;
}
};
力扣太坑了, while( i>=0 && s[i]!=' ' ) 这个条件,必须将 i>=0 放在前面,否则不能通过!!!!!!太坑了,浪费好多时间找错误。
解法2—栈
我们可以从前向后遍历字符串s,将其中的每个单词依次加入栈中,最后,再从栈中取出每一个单词,拼接成一个字符串就可以了。
class Solution
{
public:
string reverseWords(string s)
{
//解法1:双指针
string res;
for(int j=s.size()-1;j>=0;--j)
{
if(s[j]==' ')
continue;
int i=j;
while( i>=0 && s[i]!=' ' )
i--;
res.append(s.substr(i+1,j-i));
res.append(" ");
j=i;
}
if (!res.empty())
{
res.pop_back(); //删除最后一个空格
}
return res;
//解法2:栈
stack<string> st; //辅助栈
string word; //用于存放s中的每一个单词
int left=0,right=s.size()-1;
string res; //最终返回的结果
//去除s最前面的空格
while(left<=right &&s[left]==' ')
left++;
//去除s最后面的空格
while(right>=left &&s[right]==' ')
right--;
while(left<=right)
{
if( word.size()>=1 && s[left]==' ')
{
st.push(word);
word.clear();
}
else if(s[left]!=' ')
{
word+=s[left];
}
left++;
}
//跳出上面的循环后,word中存放了s中最后一个单词,还没来得及加入栈中
st.push(word);
while(!st.empty())
{
string tmp=st.top();
st.pop();
res+=tmp;
if(!st.empty()) //只要不是栈中最后一个单词,拼接完后就要加一个空格
{
res+=" ";
}
}
return res;
}
};