8. 字符串转换整数 (atoi)(自动机)
逐位判断,并且考虑各种情况
1、首先去掉头部,包括去掉空格和其他符号,直到碰到加减号或者数字
2、设置正负flag,如果是负号则flag为-1
3、用一个long型的ans从字符串最高位开始记录,一边记录一边乘以10,如果超过范围就返回INT_MAX
class Solution {
public:
int myAtoi(string s) {
//各种情况判断
int flag=1,i;long ans=0;
for(i=0;i<s.size();i++){
if(s[i]==' ')
continue;
if(s[i]=='-'||isdigit(s[i])||s[i]=='+')
break;
else return 0;
}
if(s[i]=='-')
flag=-1;
if(s[i]=='-'||s[i]=='+')
i++;
for(int j=i;j<s.size();j++) {
if(isdigit(s[j])) {
ans=ans*10+(s[j]-'0');
if(ans>INT_MAX&&flag==1) return INT_MAX;
if(ans>INT_MAX&&flag==-1) return INT_MIN;
}
else break;
}
return flag*ans;
}
};
43. 字符串相乘(模拟)
将两个字符串翻转后存储,逐位相乘最后统一处理进位,去除前导0,最后再翻转回来
class Solution {
public:
string multiply(string num1, string num2) {
vector<int> A, B;
int n = num1.size(), m = num2.size();
for (int i = n - 1; i >= 0; i -- ) A.push_back(num1[i] - '0'); //反向存贮
for (int i = m - 1; i >= 0; i -- ) B.push_back(num2[i] - '0');
vector<int> C(n + m);
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
C[i + j] += A[i] * B[j];
int t = 0; //存贮进位
for (int i = 0; i < C.size(); i ++ ) {
t += C[i];
C[i] = t % 10;
t /= 10;
}
int k = C.size() - 1;
while (k > 0 && !C[k]) k -- ; //去除前导0
string res;
while (k >= 0) res += C[k -- ] + '0'; //反转
return res;
}
};
151. 翻转字符串里的单词(原地两次翻转+一次遍历)
1、本题要求额外空间复杂度为1,所以使用原地翻转的方法
2、由于翻转后单词本身顺序不变,单词之间的顺序变了,所以采用两次翻转的方法
3、首先对整个字符串翻转,把单词之间的顺序调整正确,其次一次遍历调整单词之内字符的顺序
4、根据要求,去掉开头结尾和单词之间多余的空格,方法是遍历到单词的位置,加上一个空格即可
5、用一个idx记录新的单词的当前索引位置
class Solution {
public:
string reverseWords(string s) {
// 反转整个字符串
reverse(s.begin(), s.end());
int n = s.size();
int idx = 0;
for (int start = 0; start < n; ++start) {
if (s[start] != ' ') {
// 填一个空白字符然后将idx移动到下一个单词的开头位置
if (idx != 0) s[idx++] = ' ';
// 循环遍历至单词的末尾
int end = start;
while (end < n && s[end] != ' ') s[idx++] = s[end++];
// 反转整个单词
reverse(s.begin() + idx - (end - start), s.begin() + idx);
// 更新start,去找下一个单词
start = end;
}
}
s.erase(s.begin() + idx, s.end());
return s;
}
};
165. 比较版本号(一次遍历)
用两个指针进行一次遍历,以小数点为每段结尾,只要比较出大小就返回
class Solution {
public:
int compareVersion(string version1, string version2) {
int n1=version1.size(),n2=version2.size(),end=max(n1,n2);
for(int p1=0,p2=0;p1<end||p2<end;p1++,p2++){
int v1=0,v2=0;
while(p1<n1&&version1[p1]!='.')v1=v1*10+version1[p1++]-'0';
while(p2<n2&&version2[p2]!='.')v2=v2*10+version2[p2++]-'0';
if(v1>v2)return 1;
else if(v1<v2)return -1;
}
return 0;
}
};
179. 最大数(排序)
1、注意排序判断函数必须加static静态调用,返回值必须是bool不能是void
2、判断大小不能用a>b,必须用a+b>b+a
3、使用范围for遍历,结尾输出前判断是否全为0,过特殊用例
static bool cmp(string a,string b) {
return a+b>b+a;
}
string largestNumber(vector<int>& nums) {
vector<string> a;
string str;
for(auto i:nums)
a.push_back(to_string(i));
sort(a.begin(),a.end(),cmp);
for(auto i:a)
str+=i;
if(str[0]=='0') str="0";
return str;
}
剑指 Offer 45. 最小数(排序)
1、将int型数组逐个转为string类型,再存入string数组。
2、用sort函数对string数组从小到大排序,再逐个加到字符串上返回。
class Solution {
public:
//必须加上static,没有通过类调用
static bool cmp(string a,string b){
return a+b<b+a;
}
string minNumber(vector<int>& nums) {
//转换成字符串排序
vector<string> res;
string ans;
//加入to_string转换函数
for(auto i:nums) res.push_back(to_string(i));
//排序时设计字符串比较函数
sort(res.begin(),res.end(),cmp);
for(auto j:res) ans+=j;
return ans;
}
};
340. 至多包含 K 个不同字符的最长子串(滑动窗口)
给定一个字符串 s ,找出 至多 包含 k 个不同字符的最长子串 T ,输出子串 T 长度。
示例 1:
输入: s = “eceba”, k = 2
输出: 3
解释: 则 T 为 “ece”,所以长度为 3。
示例 2:
输入: s = “aa”, k = 1
输出: 2
解释: 则 T 为 “aa”,所以长度为 2
int func(string s, int k) {
unordered_map m;
int maxLen = 0;
int i = 0; // 快指针
int j = 0; // 慢指针
while (i < s.size()) {
if (m.size() <= k) m[s[i]]++;
while (m.size() > k) { // 当前区间不满足『至多包含k个不同字符』
if (--m[s[j]] == 0) {
m.erase(s[j]);
}
++j; // 慢指针左移
}
maxLen = max(maxLen, i - j + 1);
++i; // 快指针左移
}
return maxLen;
}
344. 反转字符串(双指针)
void reverseString(vector<char>& s) {
int n = s.size();
for (int left = 0, right = n - 1; left < right; ++left, --right) {
swap(s[left], s[right]);
}
}
415. 字符串相加(模拟)
从后往前遍历,用while,只要两个字符串和进位有一个存在就while循环,不够的补0
class Solution {
public:
string addStrings(string num1, string num2) {
int i = num1.length() - 1, j = num2.length() - 1, add = 0;
string ans = "";
while (i >= 0 || j >= 0 || add != 0) {
int x = i >= 0 ? num1[i] - '0' : 0;
int y = j >= 0 ? num2[j] - '0' : 0;
int result = x + y + add;
ans.push_back('0' + result % 10);
add = result / 10;
i -= 1;
j -= 1;
}
// 计算完以后的答案需要翻转过来
reverse(ans.begin(), ans.end());
return ans;
}
};
438. 找到字符串中所有字母异位词(滑动窗口)
1、找两个字符串是否包含,可以用滑动窗口两个指针遍历
2、至于异位词由于顺序不同,可以将字母存入数组,整体对比数组,数组不带顺序
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int>ans;
if(p.size()>s.size()||s.size()==0) return ans;
vector<int>need(128);
vector<int>windows(128);
for(char a:p) need[a]++;
for(int i=0;i<p.size()-1;i++) windows[s[i]]++;
int l=0,r=p.size()-1;//窗口是[l,r]
while(r<s.size()) {
windows[s[r++]]++;
if(windows==need) ans.push_back(l);
windows[s[l++]]--;
}
return ans;
}
};
678. 有效的括号字符串(两次遍历)
1、两次遍历,从左到右遍历一遍,用left统计,碰见左括号和*加1,碰见右括号减1
2、从右到左遍历一遍,用right统计,碰见右括号和星加1,碰见左括号减1
3、两次遍历出现一个负数就不是有效的括号字符串
class Solution {
public:
bool checkValidString(string s) {
int left = 0, right = 0, size = s.size();
for(int i = 0; i < size; ++i)
{
left += (s[i] == ')') ? -1 : +1; //从左向右看左括号能否有效
right += (s[size-1-i] == '(') ? -1 : +1; //从右向左看右括号能否有效
if(left < 0 || right < 0) return false;
}
return true;
}
};