反转字符串 II
- 普通的反转就用双指针实现就好,来看些花式反转!
- 力扣题目链接
- 解法:
string reverseStr(string s, int k) {
for(int i=0; i<s.size(); i+=2*k)
if(i+k<=s.size()) //判断是否不足k个字符
reverse(s.begin()+i, s.begin()+i+k);
else
reverse(s.begin()+i, s.end()); //全部反转
return s;
}
- 算法复杂度:时间复杂度O(n),空间复杂度O(1)
翻转字符串里的单词
- 最暴力的解法就是把单词一个个分离出来放到vector中,最后重组一个字符串
- 一种比较好的思路是去除字符串前后的空白,然后反转,然后挨个单词反转
- 力扣题目链接
- 解法1:
string reverseWords(string s) {
vector<string> words;
for(int i=0; i<s.size(); i++){
while(i<s.size() && s[i]==' ') i++;
string t="";
while(i<s.size() && s[i]!=' ') {t+=s[i]; i++;}
if(t!="") words.push_back(t);
}
string t="";
for(int i=words.size()-1; i>0; i--){
t+=words[i];
t+=" ";
}
t+=words[0];
return t;
}
- 解法2:
void reverse(string& s,int start,int end){
for(int i=start, j=end; i<j; i++, j--) swap(s[i], s[j]);
}
void removeExtraSpace(string& s){
int slow=0;
for(int i=0; i<s.size(); i++)
if(s[i]!=' '){
if(slow!=0) s[slow++]=' ';
while(i<s.size() && s[i]!=' ') s[slow++]=s[i++];
}
s.resize(slow); //slow的大小即为去除多余空格后的大小
}
string reverseWords(string s) {
removeExtraSpace(s);
reverse(s,0,s.size()-1);
int start=0;
for(int i=0;i<=s.size();i++)
if(i==s.size() || s[i]==' '){
reverse(s,start,i-1);
start=i+1;
}
return s;
}
- 算法复杂度:时间复杂度O(n),空间复杂度O(1)
右旋字符串
- 思路和上题基本相同
- 卡码网题目链接
- 解法:
#include<iostream>
using namespace std;
void reverse(string& s, int start, int end){
for(int i=start, j=end; i<j; i++, j--) swap(s[i],s[j]);
}
int main(){
string s; int k;
cin >> k >> s;
reverse(s, 0, s.size()-1);
reverse(s, 0, k-1);
reverse(s, k, s.size()-1);
cout << s;
}
- 算法复杂度:时间复杂度O(n),空间复杂度O(1)
实现 strStr()
- 搞清楚KMP算法,前缀表(PMT表)以及next数组的关系
- 力扣题目链接
- 解法1(PMT表):
int strStr(string haystack, string needle) {
int n=haystack.size(), m=needle.size();
vector<int> pi(m); //PMT表
for(int i=1, j=0; i<m; i++){
while(j>0 && needle[i]!=needle[j]) j=pi[j-1];
if(needle[i]==needle[j]) j++;
pi[i]=j;
}
for(int i=0, j=0; i<n; i++){
//失配
while(j>0 && haystack[i]!=needle[j]) j=pi[j-1];
if(haystack[i]==needle[j]) j++;
if(j==m) return i-m+1; //匹配成功
}
return -1;
}
- 解法2(next数组):
void getNext(string needle, vector<int>& next){
int i=0, j=-1; next[0]=j;
while(i<needle.size()-1)
if(j==-1 || needle[i]==needle[j]){
i++; j++;
next[i]=j;
} else j=next[j];
}
int strStr(string haystack, string needle) {
int n=haystack.size(), m=needle.size();
vector<int> next(m); //next数组
getNext(needle, next);
int i=0, j=0;
while(i<n && j<m)
if(j==-1 || haystack[i]==needle[j]) {i++; j++;}
else j=next[j];
if(j==m) return i-j;
else return -1;
}
- 算法复杂度:时间复杂度O(n),空间复杂度O(m)
重复的子字符串
- 两种想法:掐头去尾法和KMP算法
- 力扣题目链接
- 解法1:
bool repeatedSubstringPattern(string s) {
string t=s+s;
t.erase(t.begin()); t.erase(t.end()-1); //掐头去尾
if(t.find(s)!=string::npos) return true;
return false;
}
或
bool repeatedSubstringPattern(string s) {
return (s + s).find(s, 1) != s.size(); //相当于string::pos
}
- 解法2:
void getNext(vector<int>& next, string s){
int j=0; next[0]=0;
for(int i=1; i<s.size(); i++){
while(j>0 && s[i]!=s[j]) j=next[j-1];
if(s[i]==s[j]) j++;
next[i]=j;
}
}
bool repeatedSubstringPattern(string s) {
int n=s.size();
vector<int> next(n);
getNext(next, s);
if(next[n-1]!=0 && n%(n-next[n-1])==0) return true; //整除
else return false;
}
- 算法复杂度:时间复杂度O(n),空间复杂度O(n)
参考资料
[1] 代码随想录
[2] Leetcode题解