344.反转字符串
思路
直接把字符串看作线形表的顺序存取结构,反转字符串相当于逆置数组。
代码实现
class Solution {
public:
void reverseString(vector<char>& s) {
//直接当做数组处理,相当于逆置数组
int i=0,j=s.size()-1;
while(i<j){
char temp=s[i];
s[i]=s[j];
s[j]=temp;
i++;
j--;
}
}
};
时间复杂度o(n)空间复杂度o(1)
541.反转字符串II
字符串操作进阶! | LeetCode:541. 反转字符串II
思路
思路很容易,也就是在反转字符串的基础上加了一些限制条件,关键在于如何 才可以让代码更加简洁,优化在于for循环中的条件,正常情况下是i++,但是这里反转字符串是以2*k为单位的,所以可以让i+=2*k,吧2*k看作成一个小整体,然后一个小块一个小块的处理,最后在看剩下的一小部分是小于k还是大于等于k小于2k
代码实现:自己实现的版本
class Solution { public: string reverse(string s,int start,int end){ int i=start,j=end-1; while(i<j){ char temp =s[i]; s[i]=s[j]; s[j]=temp; i++;j--; } return s; } string reverseStr(string s, int k) { //写的太麻烦了 int i=0,j=2*k; while(j<s.size()){ s=reverse(s,i,i+k); j+=2*k; i+=2*k; } if(s.size()-i<k){ s=reverse(s,i,s.size()); } else if(s.size()-i>=k&&s.size()-i<=2*k){ s=reverse(s,i,i+k); } return s; } };
代码实现:优化版本 把while写成了一个for
class Solution {
public:
string reverse(string s,int start,int end){
int i=start,j=end-1;
while(i<j){
char temp =s[i];
s[i]=s[j];
s[j]=temp;
i++;j--;
}
return s;
}
string reverseStr(string s, int k) {
//简洁版本 上述逻辑可以用一个for循环实现
for(int i=0;i<s.size();i+=2*k){
if(i+k<=s.size()) s=reverse(s,i,i+k);
else s=reverse(s,i,s.size());
}
return s;
}
};
时间复杂度o(n)空间复杂度o(1)
剑指Offer 05.替换空格
思路:双指针法
先统计空格的数量,然后增长原字符串的长度,扩展好长度以后,使用双指针把空格替换为%20,具体操作为,先让一个指针i指向原字符串尾,然后j指向扩展后的字符串尾,从后向前处理(为什么从后向前,因为从前向后处理时间复杂度是o(n^2)因为为了保证顺序表的线性结果,替换过程中需要移动元素)如果i扫描到的不是空格,那么就直接覆盖到j所指的位置,如果是空格,那么j顺序插入0,2,%,然后重复上述操作,直到i小于0,就替换完成了。
代码实现
class Solution {
public:
string replaceSpace(string s) {
//双指针
int count=0;
int oldsize=s.size();
for(int i=0;i<s.size();i++){
if(s[i]==' ') count++;
}
s.resize(s.size()+2*count);
int i=oldsize-1,j=s.size()-1;
for(;i>=0;i--){
if(s[i]!=' ')s[j--]=s[i];
else{
s[j--]='0';
s[j--]='2';
s[j--]='%';
}
}
return s;
}
};
//时间复杂度o(n)空间复杂度o(1);
151.反转字符串里的单词
字符串复杂操作拿捏了! | LeetCode:151.翻转字符串里的单词
思路
就是把反转字符串,移除数组中的元素综合在了一起,思路不难,关键在于代码如何实现
代码实现:自己实现的冗余版本
class Solution { public: string reverse(string s,int start,int end){ int i=start,j=end-1; while(i<j){ char temp=s[i]; s[i]=s[j]; s[j]=temp; i++;j--; } return s; } string deletekg(string s){ int count=0;//前导空格的数量 while(s[count]==' '){ count++; } int i=0,j=count; for(;j<s.size();j++){ s[i++]=s[j]; } s.resize(i); return s; } string deleteinkg(string s){ int i=s.size()-1,j=s.size()-1; int count=0; while(i>=0){ while(s[i]==s[i+1]&&s[i]==' '){ count++; i--; } s[j--]=s[i--]; } while(count--) s[count]=' '; s=deletekg(s); return s; } string reverseWords(string s) { //先去掉前导空格,先整体反转,然后从头扫描,碰到一个单词就反转一次,再去掉前导空格 s=deletekg(s); s=reverse(s,0,s.size()); s=deletekg(s); int last=0;//上次空格之后的第一个字母的位置 for(int i=0;i<s.size();i++){ if(s[i]==' '){ s=reverse(s,last,i); last=i+1; } } s=reverse(s,last,s.size());//最后扫不到空格了 所以最后一个单词会漏处理掉 s=deleteinkg(s); return s; } };
代码实现:运用了移除数组元素的双指针操作优化了去除空格的操作
class Solution {
public:
string reverse(string s,int start,int end){
int i=start,j=end-1;
while(i<j){
char temp=s[i];
s[i]=s[j];
s[j]=temp;
i++;j--;
}
return s;
}
string reverseWords(string s) {
//简介版代码 关键在于优化了去除空格的操作 ,如何优化的和数组中的移除元素同理,使用双指针移动
int slow=0;
for(int fast=0;fast<s.size();fast++){
if(s[fast]!=' '){
if(slow!=0) s[slow++]=' ';//除了第一个单词,在每个单词前面插入一个空格
while(fast<s.size()&&s[fast]!=' '){
s[slow++]=s[fast++];
}
}
}
s.resize(slow);
s=reverse(s,0,s.size());
int last=0;//上次空格之后的第一个字母的位置
for(int i=0;i<s.size();i++){
if(s[i]==' '){
s=reverse(s,last,i);
last=i+1;
}
}
s=reverse(s,last,s.size());//最后扫不到空格了 所以最后一个单词会漏处理掉
return s;
}
时间复杂度o(n)空间复杂度o(1)
剑指Offer58-II.左旋转字符串
思路
先整体转置,然后转置0到size-n,再转置size-n到size即可完成旋转操作
代码实现
class Solution {
public:
string reverse(string s,int start,int end){
int i=start,j=end-1;
while(i<j){
char temp=s[i];
s[i]=s[j];
s[j]=temp;
i++;j--;
}
return s;
}
string reverseLeftWords(string s, int n) {
s=reverse(s,0,s.size());
s=reverse(s,0,s.size()-n);
s=reverse(s,s.size()-n,s.size());
return s;
}
};
时间复杂度o(n)空间复杂度o(1)
总结
今天的三个题没有难的算法思路,需要注意的就是一个对于字符串的操作的优化,例如移除数组元素的双指针法怎么运用到151题中的去除空格中,还有在541题中用for实现while的操作。