剑指 Offer 58 - I. 翻转单词顺序
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
为什么要写这两道题呢,因为我一开始都是写的普通做法:
class Solution {
public:
string findWord(string& s,int& pos) {
int len=s.length();
string ret="";
while(pos<len&&s[pos]!=' ') {
ret+=s[pos];
pos++;
}
return ret;
}
string reverseWords(string s) {
string ans="";
int len=s.length(),pos=0;
vector<string>word;
while(pos<len) {
if(s[pos]!=' ')
word.push_back(findWord(s,pos));
else pos++;
}
int n=word.size();
for(int i=n-1;i>0;i--) {
ans+=word[i];
ans+=' ';
}
if(n)
ans+=word[0];
return ans;
}
};
class Solution {
public:
string reverseLeftWords(string s, int k) {
int len=s.length();
string ans,tmp;
for(int i=0;i<k;i++)
tmp+=s[i];
for(int i=k;i<len;i++)
ans+=s[i];
return ans+tmp;
}
};
后来看了两道题的评论区后,我发现左旋转字符串还有不另外开辟空间的做法,也就是只使用翻转来做
class Solution {
public:
string reverseLeftWords(string s, int k) {
reverse(s.begin(),s.begin()+k);
reverse(s.begin()+k,s.end());
reverse(s.begin(),s.end());
return s;
}
};
这里还有一个需要注意到的地方,如果想先整体反转再部分反转的话,直接调换语句顺序是不够的,还需要调整部分反转的区间,因为整体反转后两部分的下标其实是会变化的
public:
string reverseLeftWords(string s, int k) {
reverse(s.begin(),s.end());
reverse(s.begin(),s.end()-k);
reverse(s.end()-k,s.end());
return s;
}
};
不使用现有函数的写法:
class Solution {
public:
void Swap(char& a,char& b) {
a^=b;
b^=a;
a^=b;
}
void Reverse(string& s,int begin,int end) {
end--;
while(begin<end) {
Swap(s[begin],s[end]);
begin++;
end--;
}
}
string reverseLeftWords(string s, int k) {
Reverse(s,0,s.length());
Reverse(s,0,s.length()-k);
Reverse(s,s.length()-k,s.length());
return s;
}
};
然后本来就这么结束了,但今天我在别人的面经里看到第一道题的不另外开辟空间做法,其实是和第二个类似的,但我之前没在第一题的评论区里看见,自己也没往那个方向想,现在想想还是缺乏了举一反三的思维。
不过第一题因为还要处理空格,所以不另外开辟空间时间复杂度会很大,不优美,我就不写了,只表述一下思路:
先对每个单词反转,再对整个句子反转,就可以获得单词内部正序,单词间反序的字符串。