1、两数之和
使用unoredred_map进行存储,注意!map的申请形式是<int,int>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int n=nums.size();
unordered_map<int,int> map1;
for(int i=0;i<n;i++){
int x=target-nums[i];
if(map1.find(x)!=map1.end()){
return {
map1[x],i};
}
else map1[nums[i]]=i;
}
return {
-1,-1};
}
};
2:两数相加
使用a记录进位,每次循环一定要将求和ans置零!!最后一定要加判断,是否最后a是1,如果是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) {
if(l1==NULL) return l2;
if(l2==NULL) return l1;
ListNode* result=new ListNode(0);
ListNode* re=result;
int ans=0,a=0;
while(l1!=NULL||l2!=NULL){
ans=0;
if(l1!=NULL){
ans+=l1->val;
l1=l1->next;
}
if(l2!=NULL){
ans+=l2->val;
l2=l2->next;
}
ans+=a;
a=ans/10==0?0:1;
re->next=new ListNode(ans%10);
re=re->next;
}
if(a==1) re->next=new ListNode(a);
return result->next;
}
};
3:无重复字符的最长子串(再刷)
这个题的关键!!使用双指针,left到right所有字符与right判断,如果没有相等的,一步步右移right,有相等的,移动left指针。全程使用len记录当前长度。
注意:每更新一次left,需要重新设置len!!!
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size()==0) return 0;
int m=s.size();
int len=0,re=0;
int left=0,right=0;
while(right<m){
for(int i=left;i<right;i++){
if(s[i]==s[right]){
left=i+1;
len=right-left;
}
}
right++;
len++;
re=max(re,len);
}
return re;
}
};
5:最长回文子串(再刷)
使用动态规划,但是需要注意:判断要使用==,而且substr用法,s.substr(开始截取位置坐标,截取长度)
class Solution {
public:
string longestPalindrome(string s) {
if(s.size()==0) return s;
int m=s.size();
vector<vector<int>> dp(m,vector<int>(m));
int start=0,len=0;
for(int i=0;i<s.size();i++){
dp[i][i]=1;
len=1;
}
for(int j=0;j<m-1;j++){
if(s[j]==s[j+1]){
dp[j][j+1]=1;
len=2;
start=j;
}
}
for(int l=3;l<=m;l++){
for(int i=0;i<=m-l;i++){
int j=i+l-1;
if(s[i]==s[j]&&dp[i+1][j-1]==1){
dp[i][j]=1;
len=l;
start=i;
}
}
}
return s.substr(start,len);
}
};
7:整数反转
使用vector容器存储,判断是否超过存储大小!
class Solution {
public:
int reverse(int x) {
if(x==0) return x;
vector<int> re;
while(x){
re.push_back(x%10);
x=x/10;
}
long ans=0;
for(int i=0;i<re.size();i++){
ans=ans*10+re[i];
if(ans>INT_MAX||ans<INT_MIN)
return 0;
}
return ans;
}
};
9:回文数
使用vector存储,记录错误:x.size(),应该是re.size()。仔细检查!!!re[right]不是right
class Solution {
public:
bool isPalindrome(int x) {
if(x==0) return true;
vector<int> re;
if(x<0) return false;
while(x){
re.push_back(x%10);
x=x/10;
}
int left=0,right=re.size()-1;
while(left<right){
if(re[left]!=re[right]) {
return false;
}
left++;
right--;
}
return true;
}
};
11:盛最多水的容器
使用双指针!左指针小,那么所有以左指针为边界的组合都小于当前情况,因为左指针固定最低高度,而宽度减少。
class Solution {
public:
int maxArea(vector<int>& height) {
int m=height.size();
if(m==0) return 0;
int left=0,right=m-1;
int ans=0,len=0;
while(left<right){
len=min(height[left],height[right])*(right-left);
ans=max(ans,len);
if(height[left]<height[right]) left++;
else if(height[left]>=height[right]) right--;
}
return ans;
}
};
14:最长公共前缀
想清楚,最长公共前缀,只要有不符合直接退出,输出前缀
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if(strs.size()==0) return "";
if(strs[0].size()==0) return "";
int m=strs[0].size();
int n=strs.size();
int a=0;
string ans;
for(int i=0;i<m;i++){
for(int j=1;j<n;j++){
if(strs[0][i]!=strs[j][i]){
a=1;
}
}
if(a==0) ans+=strs[0][i];
if(a==1) return ans;
}
return ans;
}
};
15:三数之和(再刷一遍!)
再刷一遍!注意双指针用法以及去重,同时注意while判断
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
int m=nums.size();
if(m==0) return result;
sort(nums.begin(),nums.end());
for(int i=0;i<m;i++){
if(nums[i]>0) return result;
if(i>0&&nums[i]==nums[i-1]) continue;
int left=i+1,right=m-1;
while(left<right){
if(nums[i]+nums[left]+nums[right]>0) right--;
else if(nums[i]+nums[left]+nums[right]<0) left++;
else{
result.push_back(vector<int>{
nums[i],nums[left],nums[right]});
while(left<right&&nums[left]==nums[left+1]) left++;
while(left<right&&nums[right]==nums[right-1]) right--;
left++;
right--;
}
}
}
return result;
}
};
16:最接近的三数之和
还是使用双指针法进行判断,需要制定一个判断距离的变量
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int m=nums.size();
sort(nums.begin(),nums.end());
if(m==0) return 0;
int len=INT_MAX,ans=0;
for(int i=0;i<m;i++){
int left=i+1,right=m-1;
while(left<right){
if(nums[i]+nums[left]+nums[right]==target) return target;
int x=nums[i]+nums[left]+nums[right];
if(abs(x-target)<len) {
len=abs(x-target);
ans=x;
}
if(x>target) right--;
else if(x<target) left++;
}
}
return ans;
}
};
17:电话号码的字母组合
class Solution {
public:
string path;
vector<string> result;
string letter[10]={
"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
void travel(string digits,int index){
if(index==digits.size()) {
result.push_back(path);
return;
}
int digit=digits[index]-'0';
string letters=letter[digit];
for(int i=0;i<letters.size();i++){
path.push_back(letters[i]);
travel(digits,index+1);
path.pop_back();
}
}
vector<string> letterCombinations(string digits) {
int m=digits.size();
if(m==0) return result;
travel(digits,0);
return result;
}
};
18:四数之和
使用双指针,同样必须关注括号类型,i–与i-1不同!
注意!!!left和right指针也需要循环,因此也需要使用while(left<right)判断
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int m=nums.size();
sort(nums.begin(),nums.end());
vector<vector<int>> result;
if(m==0) return result;
for(int i=0;i<m;i++){
if(i>0&&nums[i]==nums[i-1]) continue;
for(int j=i+1;j<m;j++){
if(j>i+1&&nums[j]==nums[j-1]) continue;
int left=j+1,right=m-1;
while(left<right){
int x=nums[i]+nums[j]+nums[left]+nums[right];
if(x<target) left++;
else if(x>target) right--;
else{
result.push_back(vector<int>{
nums[i],nums[j],nums[left],nums[right]});
while(left<right&&nums[left]==nums[left+1]) left++;
while(left<right&&nums[right]==nums[right-1]) right--;
left++;
right--;
}
}
}
}
return result;
}
};
19:删除链表的倒数第N个结点
使用双指针
/**
* 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* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy=new ListNode(0);
dummy->next=head;
ListNode* right=head;
for(int i=0;i<n;i++){
right=right->next;
}
ListNode* left=dummy;
while(right!=NULL){
left=left->next;
right=right->next;
}
left->next=left->next->next;
return dummy->next;
}
};
20:有效的括号
注意栈是push,不是push_back!!!
class Solution {
public:
bool isValid(string s) {
int m=s.size();
if(m==0) return true;
stack<int> re;
for(int i=0;i<m;i++){
if(s[i]=='(') re.push(')');
else if(s[i]=='{') re.push('}');
else if(s[i]=='[') re.push(']');
else if(!re.empty()&&s[i]==re.top()) re.pop();
else if(re.empty()||s[i]!=re.top()) return false;
}
if(!re.empty()) return false;
else return true;
}
};
21:合并两个有序链表
一定要加else!!!不然l1->next会判断出界
/**
* 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* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==NULL) return l2;
if(l2==NULL) return l1;
ListNode* result=new ListNode(0);
ListNode* re=result;
while(l1!=NULL||l2!=NULL){
if(l1==NULL){
re->next=l2;
l2=l2->next;
}
else if(l2==NULL){
re->next=l1;
l1=l1->next;
}
else if(l1->val<l2->val){
re->next=l1;
l1=l1->next;
}
else if(l1->val>=l2->val){
re->next=l2;
l2=l2->next;
}
re=re->next;
}
return result->next;
}
};
22:括号生成
使用回溯法!!!
认真,主函数变量名与子函数变量名不同!!!
left是左括号数量,right是右括号数量。注意不能使用引用,只在子函数里面处理输出就行
class Solution {
public:
void travel(vector<string>& ans,string a,int left,int right,int max){
if(a.size()==2*max) {
ans.push_back(a);
return;
}
if(left<max) travel(ans,a+'(',left+1,right,max);
if(left>right&&right<max) travel(ans,a+')',left,right+1,max);
}
vector<string> generateParenthesis(int n) {
vector<string> result;
if(n==0) return result;
travel(result,"",0,0,n);
return result;
}
};
24:两两交换链表中的结点
在一个循环中定义指针,想清楚每一步返回什么(返回交换后的第一个结点!!)
/**
* 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* swapPairs(ListNode* head) {
if(head==NULL||head->next==NULL) return head;
ListNode* cur=head->next;
head->next=swapPairs(cur->next);
cur->next=head;
return cur;
}
};
26:删除排序数组中的重复项
使用双指针法,nums[j]与nums[i]不断比较
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int m=nums.size();
if(m==0) return 0;
int i=0,j=0;
for(int j=0;j<m;j++){
if(nums[i]!=nums[j]){
nums[i+1]=nums[j];
i++;
}
}
return i+1;
}
};
31:下一个排列
本质上是将大的数字移到前面,但是由于必须按照顺序改变,因此尽量每次增大的最小。因此从后往前找到递增的nums[i],再找到nums[i]后最靠后的比他大的数,将两者交换,注意!同时需要将i后面排序。本质:升序变成降序!!!
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int m=nums.size();
if(m==0||m==1) return;
int i=m-2;
while(i>=0&&nums[i]>=nums[i+1]) i--;
if(i>=0){
int j=m-1;
while(j>i&&nums[i]>=nums[j]) j--;
swap(nums[i],nums[j]);
}
sort(nums.begin()+i+1,nums.end());
}
};
33:搜索旋转排序数组
一定有一半是有序数组,二分法分两种情况讨论
左闭右闭区间
class Solution {
public:
int search(vector<int>& nums, int target) {
int m=nums.size();
if(m==0) return -1;
if(m==1) return nums[0]==target?0:-1;
int left=0;
int right=m-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target) return mid;
if(nums[mid]>=nums[left]){
if(nums[left]<=target&&nums[mid]>target) right=mid-1;
else left=mid+1;
}
else{
if(nums[mid]<target&&nums[right]>=target) left=mid+1;
else right=mid-1;
}
}
return -1;
}
};
34:在排序数组中查找元素的第一个和最后一个位置
使用双指针法,但是一定要确定指针不能越界,比如加上i>=0
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int m=nums.size();
if(m==0) return {
-1,-1};
int left=0,right=m-1,ans=-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target) {
ans=mid;
break;
}
if(nums[mid]<target) left=mid+1;
else right=mid-1;
}
if(ans==-1) return {
-1,-1};
int i=ans;
while(i>=0&&nums[i]==target) i--;
int j=ans;
while(j<m&&nums[j]==target) j++;
return {
i+1,j-1};
}
};
35:搜索插入位置
双指针法,注意最后是right+1
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int m=nums.size();
if(m==0) return 0;
int left=0,right=m-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target) return mid;
if(nums[mid]<target) left=mid+1;
if(nums[mid]>target) right=mid-1;
}
return right+1;
}
};
38:外观数列(再刷一遍)
其实原理很简单,不要怕想,就是使用递归!!!一定要注意,每次其实需要i++
class Solution {
public:
string countAndSay(int n) {
if(n==1) return "1";
string pre=countAndSay(n-1),ans;
for(int i=0;i<pre.size();i++){
int j=i;
while(j<pre.size()&&pre[j]==pre[i]) j++;
ans+=to_string(j-i);
ans+=pre[i];
i=j-1;
}
return ans;
}
};
或者固定i,让j变化与i比较。注意j需要从与i相等的地方开始比较,否则无法遍历单数。最后一个数字需要比较,因此j要等于长度也可以
class Solution {
public:
string countAndSay(int n) {
if(n==1) return "1";
string pre=countAndSay(n-1),ans;
int i=0;
for(int j=0;j<=pre.size();j++){
if(pre[j]==pre[i]) continue;
ans+=to_string(j-i);
ans+=pre[i];
i=j;
j--;
}
return ans;
}
};
39:组合总和
使用回溯!注意对于一个集合求组合,需要使用index,避免重复
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void travel(vector<int> candidates,int ans,int index){
if(ans==0) {
result.push_back(path);
return;
}
if(ans<0) return;
for(int i=index;i<candidates.size();i++){
path.push_back(candidates[i]);
travel(candidates,ans-candidates[i],i);
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
int m=candidates.size();
if(m==0) return result;
travel(candidates,target,0);
return result;
}
};
进行剪枝,排序后可以直接判断需不需要进入下一递归
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void travel(vector<int> candidates,int ans,int index){
if(ans==0) {
result.push_back(path);
return;
}
if(ans<0) return;
for(int i=index;i<candidates.size()&&ans-candidates[i]>=0;i++){
path.push_back(candidates[i]);
travel(candidates,ans-candidates[i],i);
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
int m=candidates.size();
if(m==0) return result;
sort(candidates.begin(),candidates.end());
travel(candidates,target,0);
return result;
}
};
40:组合总和2
使用回溯,注意去重操作!同一层不能同时使用两次
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void travel(vector<int> candidates,int ans,int index){
if(ans==0) {
result.push_back(path);
return;
}
if(ans<0) return;
for(int i=index;i<candidates.size()&&ans-candidates[i]>=0;i++){
if(i>index&&candidates[i]==candidates[i-1]) continue;
path.push_back(candidates[i]);
travel(candidates,ans-candidates[i],i+1);
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
int m=candidates.size();
if(m==0) return result;
sort(candidates.begin(),candidates.end());
travel(candidates,target,0);
return result;
}
};
46:全排列
排列问题需要使用use数组,记录使用次数,同时需要从0开始
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void travel(vector<int>nums,vector<bool>& used){
if(path.size()==nums.size()){
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++){
if(used[i]==false) continue;
path.push_back(nums[i]);
used[i]=false;
travel(nums,used);
used[i]=true;
path.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
int m=nums.size();
if(m==0) return result;
vector<bool> used(nums.size(),true);
travel(nums,used);
return result;
}
};
48:旋转图像
自外向内一共有不超过 n/2n/2 层,从外而内顺时针循环!使用for循环
i是层数,j是上下边界,下边界为m-i-1。其中j需要小于m-1-2*i
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
if(matrix.size()==0||matrix[0].size()==0) return;
int m=matrix.size();
int s=0;
for(int i=0;m-2*i>1;i++){
//或者i<m/2
for(int j=0;j<m-1-2*i;j++){
//或者j<n+1/2
int s=matrix[i][i+j];
matrix[i][i+j]=matrix[m-1-i-j][i];
matrix[m-1-i-j][i]=matrix[m-1-i][m-1-i-j];
matrix[m-1-i][m-1-i-j]=matrix[i+j][m-1-i];
matrix[i+j][m-1-i]=s;
}
}
}
};
后续加入直接翻转
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
// 水平翻转
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < n; ++j) {
swap(matrix[i][j], matrix[n - i - 1][j]);
}
}
// 主对角线翻转
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
swap(matrix[i][j], matrix[j][i]);
}
}
}
};
49:字母异位词分组
分类题,使用哈希表,第一遍分好类,第二遍取出即可。关键是如何分类,key值怎么取!
注意变量对应
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> result;
if(strs.size()==0) return result;
unordered_map<string,vector<string>> ans;
for(int i=0;i<strs.size();i++){
string s=strs[i];
sort(s.begin(),s.end());
ans[s].push_back(strs[i]);
}
for(auto l:ans){
result.push_back(l.second);
}
return result;
}
};
50:pow(x,n)
使用递归,考虑负号!!!本题有几个坑,首先r=i*n报错,必须使用long long型,输入负数转为正数会溢出。直接给long long赋值-2147483648会出错,问题不清楚!!!
class Solution {
public:
double myPow1(double x, long long n) {
if(n==1) return x;
int w=n%2;
double s=myPow(x,n/2);
if(w==1) return s*s*x;
else return s*s;
}
double myPow(double x, int n) {
if(n==0) return 1;
int i=1;
if(n<0) i=-1;
long long r=n;
double s=myPow1(x,r*i);
if(n<0) return 1/s;
else return s;
}
};
53:最大子序和
使用动态规划,注意max1开始取值,避免只有一个数的情况
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size()==0) return 0;
vector<int> dp(nums.size());
dp[0]=nums[0];
int max1=nums[0];
for(int i=1;i<nums.size();i++){
dp[i]=max(dp[i-1]+nums[i],nums[i]);
max1=max(max1,dp[i]);
}
return max1;
}
};
54:螺旋矩阵(再刷)
参考题解中大神答案:
1、首先设定上下左右边界
2、其次向右移动到最右,此时第一行因为已经使用过了,可以将其从图中删去,体现在代码中就是重新定义上边界
3、判断若重新定义后,上下边界交错,表明螺旋矩阵遍历结束,跳出循环,返回答案
4、若上下边界不交错,则遍历还未结束,接着向下向左向上移动,操作过程与第一,二步同理
5、不断循环以上步骤,直到某两条边界交错,跳出循环,返回答案
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> ans;
int up=0,down=matrix.size()-1;
int le=0,ri=matrix[0].size()-1;
while(true){
for(int j=le;j<=ri;j++) ans.push_back(matrix[up][j]);
if(++up>down) break;
for(int i=up;i<=down;i++) ans.push_back(matrix[i][ri]);
if(--ri<le) break;
for(int j=ri;j>=le;j--) ans.push_back(matrix[down][j]);
if(--down<up) break;
for(int i=down;i>=up;i--) ans.push_back(matrix[i][le]);
if(++le>ri) break;
}
return ans;
}
};
55:跳跃游戏
每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。关键是cover是一个整体变量,能多远到达。注意:必须要小于等于cover,能最远到达的位置
class Solution {
public:
bool canJump(vector<int>& nums) {
int cover=0;
if(nums.size()==1) return true;
for(int i=0;i<=cover;i++){
cover=max(i+nums[i],cover);
if(cover>=nums.size()-1) return true;
}
return false;
}
};
45:跳跃游戏2
从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最小步数!
注意!一定要理解步数增加的条件,就是到了当前能跳到最大距离,但是没到最后,不论下一个最大距离是哪一步得到的,只要能跳到,加一就行
class Solution {
public:
int jump(vector<int>& nums) {
if (nums.size() == 1) return 0;
int curDistance = 0; // 当前覆盖最远距离下标
int ans = 0; // 记录走的最大步数
int nextDistance = 0; // 下一步覆盖最远距离下标
for (int i = 0; i < nums.size(); i++) {
nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖最远距离下标
if (i == curDistance) {
// 遇到当前覆盖最远距离下标
if (curDistance != nums.size() - 1) {
// 如果当前覆盖最远距离下标不是终点
ans++; // 需要走下一步
curDistance = nextDistance; // 更新当前覆盖最远距离下标(相当于加油了)
if (nextDistance >= nums.size() - 1) break; // 下一步的覆盖范围已经可以达到终点,结束循环
} else break; // 当前覆盖最远距离下标是集合终点,不用做ans++操作了,直接结束
}
}
return ans;
}
};
56:合并区间
排序加双指针,关键在于判断左边第二个元素与右边第一个元素的大小
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
int m=intervals.size();
vector<vector<int>> ans;
vector<int> s;
sort(intervals.begin(),intervals.end());
if(m==0) return ans;
int j,l;
for(int i=0;i<m;){
j=i+1;;
l=intervals[i][1];
while(j<intervals.size()&&intervals[j][0]<=l){
l=max(l,intervals[j][1]);
j++;
}
ans.push_back(vector<int>{
intervals[i][0],l});
i=j;
}
return ans;
}
};
61:旋转链表
各种特殊情况!!!k不一定小于size()
快慢指针
/**
* 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* rotateRight(ListNode* head, int k) {
if(head==NULL||head->next==NULL) return head;
if(k==0) return head;
ListNode* l1=head;
int c=0;
for(int i=0;i<k;i++){
l1=l1->next;
c++;
if(l1==NULL) {
l1=head;
k=c+k%c;
}
}
ListNode* l2=head;
while(l1->next){
l1=l1->next;
l2=l2->next;
}
l1->next=head;
ListNode* cur=new ListNode(0);
cur->next=l2->next;
l2->next=NULL;
return cur->next;
}
};
62:不同路径
动态规划
class Solution {
public:
int uniquePaths(int m, int n) {
if(m==0||n==0) return 0;
vector<vector<int>> dp(m,vector<int>(n));
for(int i=0;i<m;i++) dp[i][0]=1;
for(int i=0;i<n;i++) dp[0][i]=1;
for(int j=1;j<n;j++){
for(int i=1;i<m;i++){
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
};
64:最小路径和
动态规划,注意!!!一定要返回m-1,n-1
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m=grid.size(),n=grid[0].size();
if(m==0||n==0) return -1;
vector<vector<int>> dp(m,vector<int>(n));
dp[0][0]=grid[0][0];
for(int i=1;i<m;i++) dp[i][0]=dp[i-1][0]+grid[i][0];
for(int i=1;i<n;i++) dp[0][i]=dp[0][i-1]+grid[0][i];
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j]=min(dp[i-1][j]+grid[i][j],dp[i][j-1]+grid[i][j]);
}
}
return dp[m-1][n-1];
}
};
66:加一
逻辑很简单,但是需要想清楚,就是对每一位判断是否等于9
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int a=0;
if(digits[digits.size()-1]<9) {
digits[digits.size()-1]++;
return digits;
}
else {
for(int i=digits.size()-1;i>=0;i--){
if(digits[i]==9) {
digits[i]=0;
}
else {
digits[i]++;
return digits;
}
}
vector<int> result(digits.size()+1);
result[0]=1;
return result;
}
}
};
69:x的平方根
二分查找
注意类型,可能x值比较大,那么最开始迭代会出现超过Int型,使用long
class Solution {
public:
int mySqrt(int x) {
if(x==0||x==1) return x;
int le=1,ri=x,ans=0;
while(ri>=le){
int mid=le+(ri-le)/2;
if((long long)mid*mid==x) return mid;
if((long long)mid*mid<x) {
le=mid+1;
ans=mid;
}
else ri=mid-1;
}
return ans;
}
};
或者使用指数形式
class Solution {
public:
int mySqrt(int x) {
if (x == 0) {
return 0;
}
int ans = exp(0.5 * log(x));
return ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans);
}
};
70:爬楼梯
动态规划
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n+1);
if(n==1) return 1;
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=dp[i-2]+dp[i-1];
}
return dp[n];
}
};
简化:注意循环不能与变量使用一个参数!!!
class Solution {
public:
int climbStairs(int n) {
int i=0,j=1,a=0;
for(int k=1;k<=n;k++){
a=i+j;
i=j;
j=a;
}
return a;
}
};
75:颜色分类
使用库函数
class Solution {
public:
void sortColors(vector<int>& nums) {
sort(nums.begin(),nums.end());
}
};
使用两次循环求解
class Solution {
public:
void sortColors(vector<int>& nums) {
int i=0,j=0;
while(j<nums.size()){
if(nums[j]==0){
swap(nums[i],nums[j]);
i++;
}
j++;
}
j=i;
while(j<nums.size()){
if(nums[j]==1){
swap(nums[i],nums[j]);
i++;
}
j++;
}
}
};
78:子集
回溯法,记录所有节点,剩余集合为空则是叶子节点,可以返回。即index大于数组长度
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtravel(vector<int>& nums,int index){
result.push_back(path);
if(index>nums.size()-1) return;
for(int i=index;i<nums.size();i++){
path.push_back(nums[i]);
backtravel(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
backtravel(nums,0);
return result;
}
};
79:单词搜索
使用递归回溯,注意使用数组判断是否使用过
注意vector初值赋值方式。注意:::可能有好几个第一个数值,一定要确定所有情况都考虑
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
rows = board.size(), columns = board[0].size();
for(int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if (backtrack(board, word, i, j, 0)) return true; // 每个格子都进行回溯判断
}
}
return false;
}
private:
int rows, columns;
bool backtrack(vector<vector<char>>& board, string& word, int x, int y, int index) {
// 结束条件
// 越界或者当前字母位不相等
if (x >= rows || x < 0 || y >= columns || y < 0 || board[x][y] != word[index]) {
return false;
}
// 最后一个字母也相等,返回成功
if (index == word.size() - 1){
return true;
}
// 避免重复使用
board[x][y] = ' ';
// 回溯
if (backtrack(board, word, x - 1, y, index + 1)
|| backtrack(board, word, x + 1, y, index + 1)
|| backtrack(board, word, x, y - 1, index + 1)
|| backtrack(board, word, x, y + 1, index + 1))
{
return true;
}
// 如果不通,回溯至上一个状态
board[x][y] = word[index];
return false;
}
};
83:删除排序链表中的重复元素
注意考虑情况!!!要判断
/**
* 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* deleteDuplicates(ListNode* head) {
if(head==NULL) return head;
ListNode* slow=head;
while(slow&&slow->next){
if(slow->val==slow->next->val){
slow->next=slow->next->next;
}
else slow=slow->next;
}
return head;
}
};
86:分隔链表
两个头结点
/**
* 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* partition(ListNode* head, int x) {
ListNode* small=new ListNode(0);
ListNode* smallnode=small;
ListNode* large=new ListNode(0);
ListNode* largenode=large;
while(head){
if(head->val<x){
smallnode->next=head;
smallnode=smallnode->next;
}
else {
largenode->next=head;
largenode=largenode->next;
}
head=head->next;
}
smallnode->next=large->next;
largenode->next=NULL;
return small->next;
}
};
88:合并两个有序数组
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i=m-1;
int j=n-1;
int l=m+n-1;
while(i>=0||j>=0){
if(i==-1) {
nums1[l]=nums2[j];
j--;
}
else if(j==-1){
nums1[l]=nums1[i];
i--;
}
else if(nums1[i]>nums2[j]){
nums1[l]=nums1[i];
i--;
}
else if(nums1[i]<=nums2[j]){
nums1[l]=nums2[j];
j--;
}
l--;
}
}
};
92:反转链表
递归
/**
* 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* travel(ListNode* pre1,ListNode* node){
if(node==NULL) return pre1;
ListNode* cur=node->next;
node->next=pre1;
return travel(node,cur);
}
ListNode* reverseBetween(ListNode* head, int left, int right) {
if(head==NULL) return head;
ListNode* dummy=new ListNode(0);
dummy->next=head;
ListNode* pre=dummy;
int m=right-left+1;
for(int i=1;i<left;i++){
pre=pre->next;
}
ListNode* later=pre;
for(int i=0;i<m;i++){
later=later->next;
}
ListNode* l=pre->next;
ListNode* curr=later->next;
pre->next=NULL;
later->next=NULL;
pre->next=travel(NULL,l);
l->next=curr;
return dummy->next;
}
};
迭代
/**
* 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* reverseBetween(ListNode* head, int left, int right) {
int m=right-left+1;
ListNode *pre=NULL;
ListNode* result=head;
while(head&&--left){
pre=head;
head=head->next;
}
ListNode* tail=head;
ListNode* new1=NULL;
while(head&&m){
ListNode* cur=head->next;
head->next=new1;
new1=head;
head=cur;
m--;
}
tail->next=head;
if(pre) pre->next=new1;
else result=new1;
return result;
}
};
141:环形链表
快慢指针
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head==NULL) return false;
ListNode* fast=head;
ListNode* slow=head;
while(fast!=NULL&&fast->next!=NULL){
fast=fast->next->next;
slow=slow->next;
if(fast==slow) return true;
}
return false;
}
};
96:不同的二叉搜索树
动态规划!dp[i]为i对应的二叉搜索树的数量,j为遍历头结点数量
class Solution {
public:
int numTrees(int n) {
vector<int> dp(n+1);
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i]+=dp[j-1]*dp[i-j];
}
}
return dp[n];
}
};
142:环形链表2
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
int pose=0;
ListNode* fast=head;
ListNode* slow=head;
while(fast!=NULL&&fast->next!=NULL){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
ListNode* index1=fast;
ListNode* index2=head;
while(index1!=index2){
index1=index1->next;
index2=index2->next;
}
return index1;
}
}
return NULL;
}
};
144:前序遍历二叉树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void travel(TreeNode* node,vector<int>& ans){
if(node==NULL) return;
ans.push_back(node->val);
travel(node->left,ans);
travel(node->right,ans);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ans;
if(root==NULL) return ans;
travel(root,ans);
return ans;
}
};
160:相交链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
set<ListNode*> m;
while(headA){
m.insert(headA);
headA=headA->next;
}
while(headB){
if(m.find(headB)!=m.end()) return headB;
headB=headB->next;
}
return NULL;
}
};
优化:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int a=0,b=0;
ListNode* headA1=headA;
ListNode* headB1=headB;
while(headA1){
headA1=headA1->next;
a++;
}
while(headB1){
headB1=headB1->next;
b++;
}
if(a<b) {
for(int i=0;i<b-a;i++) headB=headB->next;
}
else for(int i=0;i<a-b;i++) headA=headA->next;
while(headA&&headB){
if(headA==headB) return headA;
headA=headA->next;
headB=headB->next;
}
return NULL;
}
};
206:反转链表
使用递归
/**
* 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* travel(ListNode* pre,ListNode* cur){
if(cur==NULL) return pre;
ListNode* node=cur->next;
cur->next=pre;
return travel(cur,node);
}
ListNode* reverseList(ListNode* head) {
if(head==NULL) return head;
ListNode* node=travel(NULL,head);
return node;
}
};
使用迭代
/**
* 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* reverseList(ListNode* head) {
ListNode* pre=NULL;
while(head){
ListNode* node=head->next;
head->next=pre;
pre=head;
head=node;
}
return pre;
}
};
226:反转二叉树
也可以直接使用swap
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void travel(TreeNode* node){
if(node==NULL) return ;
TreeNode* cur=node->left;
node->left=node->right;
node->right=cur;
travel(node->left);
travel(node->right);
}
TreeNode* invertTree(TreeNode* root) {
if(root==NULL) return root;
travel(root);
return root;
}
};
239:滑动窗口最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ans;
int s=INT_MIN;
if(nums.size()==0) return ans;
for(int i=0;i<=nums.size()-k;i++){
s=INT_MIN;
for(int j=0;j<k;j++){
s=max(s,nums[i+j]);
}
ans.push_back(s);
}
return ans;
}
};
使用优先队列,避免超过时间限制
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ans;
int m=nums.size();
priority_queue<pair<int,int>> q;
for(int i=0;i<k;i++){
q.emplace(nums[i],i);
}
ans.push_back(q.top().first);
for(int i=k;i<m;i++){
q.emplace(nums[i],i);
while(q.top().second<i-k+1){
q.pop();
}
ans.push_back(q.top().first);
}
return ans;
}
};
255:用队列实现栈
class MyStack {
public:
queue<int> que1;
queue<int> que2;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
que1.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
if(que1.empty()) return -1;
int m=que1.size();
for(int i=0;i<m-1;i++){
int x=que1.front();
que1.pop();
que2.push(x);
}
int x=que1.front();
que1.pop();
que1=que2;
while(!que2.empty()){
que2.pop();
}
return x;
}
/** Get the top element. */
int top() {
return que1.back();
}
/** Returns whether the stack is empty. */
bool empty() {
return que1.empty();
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
322:零钱兑换
动态规划问题
343:整数拆分
动态规划,注意!!!一定要观察,dp[i]是对i进行拆分的最大乘积,找到对应的递推关系
class Solution {
public:
int integerBreak(int n) {
vector<int> dp(n+1);
dp[2]=1;
for(int i=3;i<=n;i++){
for(int j=1;j<i-1;j++){
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
};
**
232:用栈实现队列
**
class MyQueue {
public:
stack<int> stk1;
stack<int> stk2;
/** Initialize your data structure here. */
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
stk1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
if(stk2.empty()) {
while(!stk1.empty()){
stk2.push(stk1.top());
stk1.pop();
}
}
int x=stk2.top();
stk2.pop();
return x;
}
/** Get the front element. */
int peek() {
if(stk2.empty()) {
while(!stk1.empty()){
stk2.push(stk1.top());
stk1.pop();
}
}
int x=stk2.top();
return x;
}
/** Returns whether the queue is empty. */
bool empty() {
return stk1.empty()&&stk2.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
509:斐波那契数
使用动态规划,注意一定要看边界,要么dp设置大点要么判断n为0情况
class Solution {
public:
int fib(int n) {
vector<int> dp(n+5);
dp[0]=0;
dp[1]=1;
for(int i=2;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};