1.链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int t=0;
ListNode* l,* r;//l是结果链表的头,r是尾
l=r=new ListNode(-1);//虚拟头节点
while(l1||l2||t){//位上有数字或者进位都得加进结果中
if(l1){//第一个数字还有数字
t+=l1->val;
l1=l1->next;
}
if(l2){//第二个数字还有数字
t+=l2->val;
l2=l2->next;
}
r=r->next=new ListNode(t%10);//只取个位出来进结果链表
t=t/10;//十位进位掉
}
return l->next;
}
};
2.双指针
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int N=s.size();
unordered_map<char,int> hash;//记录i-j之间字母出现次数
int res=0;
for(int i=0,j=0;i<N;i++){//i在后,j在前
while(hash[s[i]]) hash[s[j++]]--;
//只要发现新增的字母在原区间已存在
//就用j来找之前和现在加进来的i重的,边找边吐
//反证法知道j只可能往后走
hash[s[i]]++;//铲出原来重复的字母后自己进去
res=max(res,i-j+1);//更新结果
}
return res;
}
};
3.贪心
class Solution {
public:
string longestPalindrome(string s) {
int N=s.size();
string res;//可用dp,但是dp得多开数组空间大,有点难
for(int i=0;i<N;i++){//遍历对称中心
int l=i-1,r=i+1;//奇数长度的遍历
while(l>=0&&r<N&&s[l]==s[r]) l--,r++;
if(r-l-1>res.size()) res=s.substr(l+1,r-l-1);
//l+1,r-1里的才是要的部分,
//因为上面是不相等时退出来的
l=i,r=i+1;//偶数长度的遍历
while(l>=0&&r<N&&s[l]==s[r]) l--,r++;
if(r-l-1>res.size()) res=s.substr(l+1,r-l-1);
}
return res;
}
};
4.找规律
class Solution {
public:
string convert(string s, int numRows) {
string res;
int N=s.size();
if(numRows==1) return s;//特殊情况,间隔变成0了,下面会死循环
for(int i=0;i<numRows;i++){
if(i==0||i==numRows-1){//第一行和最后一行
for(int j=i;j<N;j+=2*numRows-2){
//这个2*x-2得画图标下标看才能找这个规律出来
res+=s[j];
}
}else{//2*numRows-2-i这个也是规律出来的,画图就知道
for(int j=i,k=2*numRows-2-i;
j<N||k<N;j+=2*numRows-2,k+=2*numRows-2){
//画图标下标看规律
if(j<N) res+=s[j];//要加判断,不然可能下标越界
if(k<N) res+=s[k];
}
}
}
return res;
}
};
5.位运算
// class Solution {
// public:
// int reverse(int x) {
// long n=0;//long是钻空子,64位不能用
// while(x!=0){
// n=n*10+x%10;
// x/=10;
// }
// return (int)n==n?n:0;
// }
// };
class Solution {
public:
int reverse(int x) {
int n=0;//long是钻空子,64位不能用
while(x){
if(n>0&&n>(INT_MAX-x%10)/10) return 0;
//加上后会溢出,
//移到等式另一边缩小溢出值来判断就可以了
if(n<0&&n<(INT_MIN-x%10)/10) return 0;
n=n*10+x%10;
//数学%的结果永远是正数,计算机是正负都行,歪打正着这题
//所以不用判断符号
x/=10;
}
return n;
}
};
6.位运算
class Solution {
public:
int myAtoi(string s) {
int N=s.size();
int k=0;
while(s[k]==' ') k++;//前导空格
int st=1;
if(s[k]=='-') st=-1,k++;
else if(s[k]=='+') k++;//符号判断
// long long res=0;
int res=0;
while(k<N&&s[k]>='0'&&s[k]<='9'){
int x=s[k]-'0';
if(st>0&&res>(INT_MAX-x)/10) return INT_MAX;
//超过最大值,和上一题一样判断溢出
//不用try-catch了
if(st<0&&-res<(INT_MIN+x)/10) return INT_MIN;
//小于最小值
if(-res*10-x==INT_MIN) return INT_MIN;
//因为最小值的绝对值比最大值大1,
//正数最大值装不下负数最大值绝对值,所以遇到就不装返回
res=res*10+x;
k++;
// if(res>INT_MAX) break;
}
res*=st;
// if(res>INT_MAX) return INT_MAX;
// if(res<INT_MIN) return INT_MIN;
return res;
}
};
7.贪心
class Solution {
public:
int maxArea(vector<int>& height) {
int res=0;
for(int l=0,r=height.size()-1;l<r;){
int h=min(height[l],height[r]);
res=max(res,(r-l)*h);
if(height[l]<height[r]){
//值小的指针向内移动,这样就减小了搜索空间
//因为面积取决于指针的距离与值小的值乘积,
//如果值大的值向内移动,距离一定减小,
//而求面积的另外一个乘数一定小于等于值小的值,
//因此面积一定减小,
//而我们要求最大的面积,因此值大的指针不动,
//而值小的指针向内移动遍历
l++;
}else{
r--;
}
}
return res;
}
};
8.找规律
class Solution {
public:
string intToRoman(int num) {
string a[]={"I","IV","V","IX","X","XL","L","XC","C","CD","D","CM","M"};
int b[]={
1,4,5,9,
10,40,50,90,
100,400,500,900,
1000
};//模拟题找规律
string res;
for(int i=12;i>=0;i--){
//查表,够就减数字加字符
while(num>=b[i]){
num-=b[i];
res+=a[i];
}
}
return res;
}
};
9.双指针
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
//双指针必须先排序
vector<vector<int>> res;
int N=nums.size();
for(int i=0;i<N;i++){//i指的为固定值
if(i&&nums[i]==nums[i-1]) continue;
//相同跳过,枚举过了
for(int j=i+1,k=N-1;j<k;j++){//双指针
if(j>i+1&&nums[j]==nums[j-1]) continue;
//相同跳过,枚举过了
while(j<k-1&&nums[j]+nums[i]+nums[k]>0) k--;
//看要不要走下一步,直到走不了
if(nums[i]+nums[j]+nums[k]==0){
res.push_back({nums[i],nums[j],nums[k]});
}
}
}
return res;
}
};
10.双指针
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
pair<int,int> res(INT_MAX,INT_MAX);
//first是差值,second是总和
int N=nums.size();
for(int i=0;i<N;i++){
for(int j=i+1,k=N-1;j<k;j++){
while(j<k-1&&nums[i]+nums[j]+nums[k-1]>=target) k--;
//第一种情况大于目标值:
//缩小距离,一直走到不能走为止
int sum=nums[i]+nums[j]+nums[k];
res=min(res,make_pair(abs(sum-target),sum));
//有可能走完了都没找到大的情况
//那就是负数了,所以要绝对值
if(k-1>j){
//第二种情况小于目标值:看看下一步还有得走吗
//,有就拿来判断第二种情况
sum=nums[i]+nums[j]+nums[k-1];
res=min(res,make_pair(target-sum,sum));
//必定小于目标值,所以不用绝对值
}
}
}
return res.second;
}
};