描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“nowcoder. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a nowcoder.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
数据范围: 1 ≤ n ≤ 100
进阶:空间复杂度 O(n) ,时间复杂度 O(n) ,保证没有只包含空格的字符串
示例1
输入: "nowcoder. a am I"
返回值: "I am a nowcoder."
示例2
输入: ""
返回值:""
方法一: 原地操作法
解题思路:将后面的字符插入到前面。
主要思路:
-
使用两个指针:
cur_end与 cur_insert , cur_end
表示当前字符串末尾位置,cur_insert表示当前插入位置。 -
从尾至头处理str,cur_end分为三种情况
- 如果cur_end指向的是空字符且上次处理的字符非空,那么将cur_end指向的字符插入到cur_insert同时删除cur_end所指字符。
- 如果cur_end指向非空字符,那么cur_end指向的字符插入到cur_insert同时删除cur_end所指字符。
- 如果cur_end指向空字符且上一次处理的字符也为空字符,那么直接删除cur_end所指字符。
代码
class Solution {
public:
string ReverseSentence(string str) {
if(str=="") return str;
int cur_insert = 0; //插入位置
int cur_end = str.size()-1;
int former_pro = 1; //上次处理的字符是否为空格
int num = 0; //处理个数;
for(int i = str.size();i>0;i--)
{
if(former_pro && str[cur_end] ==' ')
{
str.erase(cur_end--,1);
former_pro = 1;
}
else if(!former_pro && str[cur_end]==' ')
{
cur_insert = num++;
str.insert(cur_insert++,1,str[cur_end++]);
str.erase(cur_end--,1);
former_pro = 1;
}
else
{
num++;
//连续的单词插入位置不能变,不然单词就会是反的
str.insert(cur_insert,1,str[cur_end++]);
str.erase(cur_end--,1);
former_pro = 0;
}
}
return str;
}
};
运行时间:6ms
超过0.97% 用C++提交的代码
占用内存:572KB
超过19.23%用C++提交的代码
复杂度分析:时间复杂度:O(N)
空间复杂度:O(1)
方法二:双指针
解题思路: 利用两个指针标识一个单词。
主要思路:
-
从尾往头遍历 使用left表示一个单词的起始位置,right表示一个单词的终止位置。
-
当遇到空格left与right同时向前移动,当遇到字符只有left向前移动,截取[left+1,right] 子串。
-
拼接截取下的字符串。
int left = str.size() - 1;
int right = str.size() - 1;
string result = "";
while (left >= 0)
{
while (str[left] == ' ')
{
--left;
--right;
if (left < 0) //越界
{
break;
}
}
if (left < 0) //越界
{
break;
}
while (str[left] != ' ')
{
--left;
if (left < 0) //越界
{
break;
}
}
result = result + str.substr(left + 1, right - left) + " ";
right = left;
}
return result.substr(0, result.size() - 1); // 结果后面会多一个空格
运行时间:5ms
超过2.06% 用C++提交的代码
占用内存:528KB
超过24.35%用C++提交的代码
复杂度分析:时间复杂度: O(N)
空间复杂度: O(N)
方法三:使用库函数stringstream
首先需要进行预处理,判断输入字符串是不是全部空格,如果是,直接输出字符串。否则,我们看如下图:
由图片可知,我们只需要先把每个单词拆分出来,然后以单词为翻转单元,即可得到结果串。
实现方式:
我们用stringstream可以实现拆分每个单词,具体代码如下:
class Solution {
public:
string ReverseSentence(string str) {
// 预处理
if (str.empty()) return str;
int i = 0, sz = str.size();
while(i < sz && str[i] == ' ') ++i;
if (i == sz) return str;
istringstream ss(str);
vector<string> ret;
string s;
// 拆分单词
while (ss >> s)
ret.push_back(s);
reverse(ret.begin(), ret.end());
ostringstream oss;
// 合并成字符串
for (int i=0; i<ret.size()-1; ++i)
oss << ret[i] << ' ';
oss << ret.back();
return oss.str();
}
};
运行时间:3ms
超过31.79% 用C++提交的代码
占用内存:700KB
超过12.09%用C++提交的代码