学习来源:
代码随香炉:https://www.programmercarl.com/
labuladong算法:https://labuladong.github.io/algo/
字符串
把字符串转换成整数(atoi)
思路:
既然是将字符串转化为数字,那我们可以遍历字符串,一个字符串,一个字符地检查,然后取出掉无用的,取出数字,利用如下代码,一个数字一个数字地转换,前面的扩大十倍加上后面一位。
res = res * 10 + sign * (c - ‘0’);
具体做法:
step 1:遍历字符串,用index记录全程的下标。
step 2:首先要排除空串,然后越过前导空格,以及前导空格后什么都没有就返回0.
step 3:然后检查符号,没有符号默认为正数。
step 4:再在后续遍历的时候,将数字字符转换成字符,遇到非数字则结束转换。
step 5:与Int型最大最小值比较,检查越界情况。
class Solution {
public:
int StrToInt(string s) {
int res = 0;
int index = 0;
int n = s.length();
//去掉前导空格,如果有
while(index < n){
if(s[index] == ' ')
index++;
else
break;
}
//去掉空格就什么都没有了
if(index == n)
return 0;
int sign = 1;
//处理第一个符号是正负号的情况
if(s[index] == '+')
index++;
else if(s[index] == '-'){
index++;
sign = -1;
}
//去掉符号就什么都没有了
if(index == n)
return 0;
while(index < n){
char c = s[index];
//后续非法字符,截断
if(c < '0' || c > '9')
break;
//处理越界
if(res > INT_MAX / 10 || (res == INT_MAX / 10 && (c - '0') > INT_MAX % 10))
return INT_MAX;
if(res < INT_MIN / 10 || (res == INT_MIN / 10 && (c - '0') > -(INT_MIN % 10)))
return INT_MIN;
res = res * 10 + sign * (c - '0');
index++;
}
return res;
}
};
反转字符串
utility iostream algorithm 都有 swap c++11改在了al…
双指针 交换首尾
class Solution {
public:
void reverseString(vector<char>& s) {
int i = 0;
int j = s.size()-1;
while(i<=j){
swap(s[i],s[j]);
i++;
j--;
}
}
};
反转字符串II (每2k 对前k 个字符反转)
其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。
当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。
所以当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。
替换空格 (用%20替换’ ')
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
// 统计空格的个数 // 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
// 从后先前将空格替换为"%20"
1. 使用额外的辅助空间:
class Solution {
public:
string replaceSpace(string s) {
string str;
for(auto c:s){
if(c==' '){
str+="%20";
}else{
str+=c;
}
}
return str;
}
};
2. 不适用额外辅助空间
翻转字符串中的单词
(代码较多 细节)
先移除多余空格 再反转整个字符串 然后再翻转单词 (整体+局部)
- split函数分割,然后反转,再join
#include<sstream>
istringstream sin(string);
while(gelint(sin,str,',')){
res.push_back(str);
}
- 双指针
思路: 整体翻转+ 局部翻转- 移除多余空格
- 将整个字符串反转
- 将每个单词反转
// 版本一
class Solution {
public:
// 反转字符串s中左闭又闭的区间[start, end]
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
swap(s[i], s[j]);
}
}
// 移除冗余空格:使用双指针(快慢指针法)O(n)的算法
void removeExtraSpaces(string& s) {
int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
// 去掉字符串前面的空格
while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
fastIndex++;
}
for (; fastIndex < s.size(); fastIndex++) {
// 去掉字符串中间部分的冗余空格
if (fastIndex - 1 > 0
&& s[fastIndex - 1] == s[fastIndex]
&& s[fastIndex] == ' ') {
continue;
} else {
s[slowIndex++] = s[fastIndex];
}
}
if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // 去掉字符串末尾的空格
s.resize(slowIndex - 1);
} else {
s.resize(slowIndex); // 重新设置字符串大小
}
}
string reverseWords(string s) {
removeExtraSpaces(s); // 去掉冗余空格
reverse(s, 0, s.size() - 1); // 将字符串全部反转
int start = 0; // 反转的单词在字符串里起始位置
int end = 0; // 反转的单词在字符串里终止位置
bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
for (int i = 0; i < s.size(); i++) { // 开始反转单词
if (!entry) {
start = i; // 确定单词起始位置
entry = true; // 进入单词区间
}
// 单词后面有空格的情况,空格就是分词符
if (entry && s[i] == ' ' && s[i - 1] != ' ') {
end = i - 1; // 确定单词终止位置
entry = false; // 结束单词区间
reverse(s, start, end);
}
// 最后一个结尾单词之后没有空格的情况
if (entry && (i == (s.size() - 1)) && s[i] != ' ' ) {
end = i;// 确定单词终止位置
entry = false; // 结束单词区间
reverse(s, start, end);
}
}
return s;
}
};
左旋字符串(把前n个字符串移动到末尾)
局部翻转 + 整体翻转 = 左旋转
具体步骤为:
反转区间为前n的子串
反转区间为n到末尾的子串
反转整个字符串
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.begin() + n);
reverse(s.begin() + n, s.end());
reverse(s.begin(), s.end());
return s;
}
};
实现strStr() (KMP算法)
前缀:包含首字母不包含尾字母的所有串
后缀:包含尾字母不包含首字母的所有串
前缀表: next数组 遇到冲突 告诉我们回退到哪里
最长相等前后缀:
class Solution {
public:
void getNext(int* next, const 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;
}
}
int strStr(string haystack, string needle) {
if (needle.size() == 0) {
return 0;
}
int next[needle.size()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
while(j > 0 && haystack[i] != needle[j]) {
j = next[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == needle.size() ) {
return (i - needle.size() + 1);
}
}
return -1;
}
};
重复的子字符串 (s可以由多个串重复得到)
字符串相乘 (数字乘法)
数字太大,直接相乘会发生益处,因此采用数字乘法进行。
- 索引从0开始
num1[i] 和 num2[j] 的乘积对应的就是 res[i+j] 和 res[i+j+1] 这两个位置。