在之前的笔记中,做反转字符串时用到了双指针的方法,做到可以将一个字符串快速颠倒的方法,这个方法可以用来处理很多关于旋转字符串的问题。
例如:Leetcode.151 颠倒字符串中的单词
给你一个字符串 s ,颠倒字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
我们第一时间的想到最快解决的方法就是,从后向前读字符串,每读完一个单词就将该单词赋给新的字符串。
class Solution {
public:
string reverseWords(string s) {
string result ="";
int j = 0;
int i = 0;
while(i < s.size())
{
while(s[i] == ' ')
{
i++;
if(i == s.size())
{
result = result.substr(1);
return result;
}
}
j = i;
while(s[i]!= ' ' )
{
i++;
if(i == s.size())
{break;}
}
if(i<s.size())
{result =" " + s.substr(j,i-j) + result;}
else
{
result = s.substr(j,i-j) + result;
}
}
return result;
}
};
但是这样就难免会浪费许多内存空间
那我们就可以使用之前提到的反转字符串的方法,解决这个问题很简单,我们只需要将整个字符串反转一下,然后将每个单词再反转一下就可以完成这个工作。
但是我们必须提前处理一下多余的空格,比如’’ hello world’'我们需要将hello前的多余空格清除掉,这就要用数组删除中用到的双指针法,利用快慢两个指针删除多余空格。
class Solution {
public:
void reverse(string& s,int start,int end)
{
for(int i=start,j=end;i<j;i++,j--)
{
swap(s[i],s[j]);
}
}
void removespace(string& s)
{
int slow = 0,fast = 0;
while(fast < s.size()-1 && s[fast] == ' ')
{
fast++;
}
for(;fast<s.size();fast++)
{
if(fast > 1 && s[fast] == s[fast-1] && s[fast] == ' ')
{continue;}
else{s[slow++] = s[fast];}
}
if(slow-1>0 && s[slow-1] == ' ')
{
s.resize(slow-1);
}
else
{
s.resize(slow);
}
}
string reverseWords(string s) {
removespace(s);
reverse(s,0,s.size()-1);
int fast = 0,slow = 0;
for(;fast<s.size();fast++)
{
while(fast< s.size() && s[fast] != ' ')
{fast++;}
reverse(s,slow,fast-1);
slow = fast + 1;
}
return s;
}
};
内存空间的使用和运行速度得到了大大的提升。
同样这个方法我们关于左旋字符这题也可以大大优化我们的代码:
Leetcode.剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”
最简单的想法当然是使用substr,这个库函数相当方便
class Solution {
public:
string reverseLeftWords(string s, int n) {
s = s.substr(n) + s.substr(0,n);
return s;
}
};
但是提升一下本题的难度,只修改本字符串不申请额外空间的话,很显然旋转字符的方式很好,我们还是直接旋转整个字符串,然后将0-s.size()-n-1的字符反转回去,再将s.size()-n-1到s.size()-1的字符串反转回来,就完成本题的要求了,直接在本字符串上修改并没有申请额外空间。
class Solution {
public:
void resver(string& s,int start,int end)
{
for(int i = start,j = end;i<j;i++,j--)
{swap(s[i],s[j]);}
}
string reverseLeftWords(string s, int n) {
resver(s,0,s.size()-1);
resver(s,0,s.size()-n-1);
resver(s,s.size()-n,s.size()-1);
return s;
}
};