我忘记C++对string操作的接口函数了
例如string如何填充字符。C++ string可以使用下标操作
541 反转字符串 【双指针】
class Solution {
public:
void reverStr(string& s, int start, int end) {
char tmp;
while(start < end) {
tmp = s[end];
s[end] = s[start];
s[start] = tmp;
start++;
end--;
}
}
string reverseStr(string s, int k) {
int l = 0;
int m = k - 1;
int r = 2 * k - 1;
while(r < s.size()) {
reverStr(s, l, m);
l = r + 1;
m = l + k - 1;
r += 2 * k;
}
if(s.size() - l < k) {
reverStr(s, l, s.size() - 1);
} else {
reverStr(s, l, l + k - 1);
}
return s;
}
};
卡码网 替换字符串中的数字
卡码网54 替换数字
思路:使用双指针替换,注意对C++ String进行resize
#include <iostream>
using namespace std;
int main() {
string input;
cin >> input;
// 怎么判断char是字母还是数字啊
int cnt = 0;
for(int i = 0; i < input.size(); i++) {
if(input[i] <= '9' && input[i] >= '0') {
cnt++;
}
}
int old = input.size() - 1;
input.resize(input.size() + cnt *5);
int end = input.size() - 1;
while(old > -1) {
if(input[old] <= '9' && input[old] >= '0') {
input[end--] = 'r';
input[end--] = 'e';
input[end--] = 'b';
input[end--] = 'm';
input[end--] = 'u';
input[end--] = 'n';
old--;
} else {
input[end--] = input[old--];
}
}
cout << input << endl;
}
151 反转字符串中的单词【双指针】
leetcode 151
思路: 可以使用先把整个字符串删除空格,再把整个字符串反转,再挨个反转单词的方式。也可以直接采用双指针的方式反转字符串。
//解法1
class Solution {
public:
string reverseWords(string s) {
// 1 先删除所有空格
// 2 把整个字符串反转
// 3 反转每个单词
// 1 删除所有空格用快慢指针
int slow = 0;
for(int fast = 0; fast < s.size(); fast++) {
if (fast == 0 && s[fast] == ' ') {
continue;
} else if (s[fast] != ' ') {
s[slow++] = s[fast];
} else if (s[fast] == ' ' && s[fast - 1] != ' ') {
s[slow++] = ' ';
} else {
continue;
}
}
if(s[slow - 1] == ' ') slow--;
s.resize(slow);
cout << s << endl;
int start = 0;
int end = s.size() - 1;
while(start < end) {
swap(s[start], s[end]);
start++;
end--;
}
cout << s;
int s1 = 0;
int e = 0;
while(e < s.size()) {
if(s[e] != ' ' && e != (s.size() - 1)) {
e++;
continue;
} else if(s[e] == ' ' || e == (s.size() - 1)){
start = s1;
if(s[e] == ' ') {
end = e-1;
} else {
end = e;
}
while(start < end) {
swap(s[start], s[end]);
start++;
end--;
}
e++;
s1 = e;
}
}
return s;
return s;
}
};
解法2:直接使用双指针
class Solution {
public:
string reverseWords(string s) {
string result;
int start = 0;
int wordEnd = s.size() - 1;
int wordLen = 0;
int i;
// 从后向前扫描string s中的char
while(wordEnd > -1) {
if(s[wordEnd] == ' ' && wordLen != 0) {
// 遇到空格,且当前扫描到的word不为空
i = 1;
//cout << "word len is" << wordLen << endl;
while(i <= wordLen) {
result.push_back(s[wordEnd + i]);
i++;
}
wordEnd--;
wordLen = 0;
result.push_back(' ');
} else if(s[wordEnd] == ' ' && wordLen == 0) {
wordEnd--;
continue;
} else {
wordEnd--;
wordLen++;
}
}
if(wordLen != 0) {
//cout << "word len is" << wordLen << endl;
i = 1;
while(i <= wordLen) {
result.push_back(s[wordEnd + i]);
i++;
}
result.push_back(' ');
}
result.pop_back();
return result;
}
};
Kama 55 右旋字符串
#include<iostream>
using namespace std;
int main() {
int n;
string s;
cin >> n;
cin >> s;
if ( n > s.size() ) {
return 0;
}
int begin = 0;
int end = s.size()-1;
while( begin < end ) {
swap(s[begin++], s[end--]);
}
begin = 0;
end = n - 1;
while( begin < end ) {
swap(s[begin++], s[end--]);
}
begin = n;
end = s.size() - 1;
while( begin < end ) {
swap(s[begin++], s[end--]);
}
cout << s;
}
leet 28 找出字符串中第一个匹配的下标 【KMP算法】
思路
KMP解法:通过已经掌握的信息去规避重复的字符串匹配操作
理解KMP前缀表的含义很重要
KMP前缀表:记录需匹配字符串needle中每个位置存在的最大相同前后缀的长度。
有了需匹配字符串needle的最大前后缀的信息,在haystack中匹配的时候,若haystack中出现匹配错误时,
就可直接跳过匹配错误部分的后缀字符串 与 前缀字符串 相同的部分。而这个跳过的字符串的长度是多少,就是由KMP数组记录的。
求KMP算法的前缀表的方法:
class Solution {
public:
int strStr(string haystack, string needle) {
if (needle.size() > haystack.size()) return -1;
if (needle.size() == 0) return 0;
int result = -1;
//使用kmp算法, 时间复杂度还是O(n * m)
// 第一步,先求出前缀表
// 使用双指针法构建 needle 的前缀数组 kmp[]
int preFixLen= 0; // preFixLen:当前共同前后缀的长度
int i = preFixLen + 1;
int kmp[needle.size()];
kmp[0] = 0;
while(i < needle.size()) {
if (needle[i] == needle[preFixLen]) {
// 当前char相同,则 共同前后缀长度++
kmp[i] = preFixLen + 1;
preFixLen++;
i++;
} else {
while(needle[preFixLen] != needle[i] && preFixLen > 0) {
// 如果当前char不相同,则通过回退前缀数组kmp[]
// 利用前缀数组中的已知信息,找到新的前后缀数组
preFixLen = kmp[--preFixLen];
}
if(needle[i] == needle[preFixLen]) {
// 若找到了共同前缀,则从该preFixLen继续计算kmp数组
kmp[i] = preFixLen + 1;
i++;
preFixLen++;
} else {
// 未匹配,则从0开始,重新计算前缀
kmp[i] = 0;
i++;
}
}
}
// 利用前缀数组进行匹配
int p1 = 0, p2 = 0;
while( p1 < haystack.size() ) {
if( haystack[p1] == needle[p2] ) {
if(p2 == needle.size() - 1) {
return p1 - (needle.size() - 1);
} else {
p1++;
p2++;
}
} else {
while( p2 > 0 && haystack[p1] != needle[p2] ) {
p2 = kmp[p2 - 1];
}
if( haystack[p1] == needle[p2]) {
p1++;
p2++;
} else {
p1++;
}
}
}
return result;
}
};
459 重复的子字符串
思路
这题也用到了KMP算法的KMP数组,只不过判断是否是由重复字符串组成时,首先要判断KMP数组最后一位不为0,即字符串存在最大相同前后缀。 其次该字符串的 子字符串的长度,应该为 s.size() - kmp[s.size() -1], 子字符串的长度要能被整个字符串长度整除才行。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
// 该字符串的KMP数组,应该满足KMP数组的最后一个数不为0,且KMP数组的长度应该是 值为0的字符串前缀的整数倍
if(s.size() == 1) return false;
int kmp[s.size()];
int preFixLen = 0;
int subStrLen = 0;
kmp[preFixLen] = 0;
for(int i = preFixLen + 1; i < s.size(); i++) {
if(s[i] == s[preFixLen]) {
kmp[i] = ++preFixLen;
} else {
while(preFixLen > 0 && s[i] != s[preFixLen]) {
preFixLen = kmp[--preFixLen];
}
if(s[i] == s[preFixLen]) {
kmp[i] = ++preFixLen;
} else {
kmp[i] = 0;
}
}
}
if(kmp[s.size() - 1] == 0) return false;
subStrLen = s.size() - kmp[s.size() - 1];
if((s.size() % subStrLen == 0)) {
return true;
} else {
return false;
}
}
};