最近两个多月一直在刷题,150道力扣题2~3遍
我的力扣地址:wsg_leetcode
//1.两数之和 vector<int> twoSum(vector<int>& nums, int target){ //哈希 unordered_map<int,int> hash; for(int i=0; i<nums.size(); i++){ int key=target-nums[i]; if(hash.count(key)>0){ return {hash[key], i}; } hash[nums[i]]=i; } return {}; } //2.两数相加 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2){ ListNode* dummy = new ListNode(-1); //定义返回列表的头节点 ListNode* head=dummy; //移动指针 int sum =0; bool carry=false; //进位 while(l1 != NULL || l2 != NULL){ sum=carry ? 1:0; if(l1 != NULL){ sum+=l1->val; l1=l1->next; } if(l2 != NULL){ sum+=l2->val; l2=l2->next; }
carry=sum/10 ? true:false; head->next=new ListNode(sum%10); head=head->next; } if(carry) h->next=new ListNode(1); return head->next; } //7.整数反转 % / int reverse(int x){ int rev=0; while(x != 0){ int pop = x%10; //如果x是负的那么pop值也是负的 x=x/10; if(rev > INT_MAX/10 || (rev==INT_MAX/10 && pop > INT_MAX%10)) return 0; //正数越界 if(rev < INT_MIN/10 || (rev==INT_MIN/10 && pop < INT_MIN%10)) return 0; //负数越界 rev = rev*10+pop; } return rev; } //3.无重复字符的最长子串 int lengthOfLongestSubstring(stirng s){ if(s.size() == 0) return 0; unordered_set<char> lookup; int maxStr=0; int left = 0; for(int i=0; i< s.size(); i++){ while(lookup.find(s[i]) != lookup.end()){ lookup.erase(s[left]); //从左端开始移除,直到不重复为止 left++; } maxStr = max(maxStr, i-left+1); lookup.insert(s[i]); } return maxStr; } //206.反转链表 //迭代 ListNode *reverseList(ListNode* head){ ListNode *prev=nullptr,*next; while(head){ next=head->next; head->next=prev; prev=head; head=next; } return prev; } //递归 ListNode *reverseList(ListNode* head){ if(head==nullptr || head->next==nullptr){ return head; } ListNode* cur=reverseList(head->next); head->next->next=head; head->next=nullptr; return cur; } //5.最长回文子串 中心扩散法 string longestPalindrome(string s){ int start=0; end=0; for(int i=0; i<s.size(); i++){ auto[left1, right1] = expandAroundCenter(s, i, i); //奇数 auto[left2, right2] = expandAroundCenter(s, i, i+1); //偶数 if(right1-left1 > end-start){ start=left1; end=right1; } if(right2-left2 > end-start){ start=left2; end=right2; } } return s.substr(start, end-start+1); } pair<int, int> expandAroundCenter(const string& s, int left, int right){ while(left >= 0 && right < s.size() && s[left] == s[right]){ left--; right++; } return {left+1, right-1}; } //70.爬楼梯 动态规划 dp[n]=dp[n-1]+dp[n-2] int climbStairs(int n){ if(n<=2) return n; vector<int> dp(n, 0); //开辟空间 dp[0]=1; dp[1]=2; for(int i=2;i<n;i++){ dp[i]=dp[i-1]+dp[i-2]; } return dp[n-1]; } //15.三数之和 排序+双指针 vector<vector<int>> threeSum(vector<int>& nums){ int n=nums.size(); sort(nums.begin(), nums.end()); vector<vector<int>> ret; for(int i=0; i<nums.size(); i++){ if(nums[i]>0) return ret; if(i>0 && nums[i]==nums[i-1]) continue; //去重 //双指针在nums[i]后面的区间寻找和为0-nums[i]的另外两个数 int l=i+1,r=n-1; while(l<r){ if(nums[l]+nums[r] == -nums[i]){ ret.push_back({nums[i], nums[l], nums[r]}); l++; r--; while(l<r && nums[l]==nums[l-1]) l++; while(l<r && nums[r]==nums[r+1]) r--; }else if(nums[l]+nums[r] > -nums[i]){ r--; }else{ l++; } } } return ret; } //46.全排列 回溯 //易理解,易变形版 void backtracking(const vector<int>& nums, vector<bool>& used, vector<int>& path, vector<vector<int>>& result){ if(path.size()==nums.size()){ result.push_back(path); return; } for(int i=0; i<nums.size(); i++){ if(used[i]) continue; path.push_back(nums[i]); used[i]=true; backtracking(nums, used); path.pop_back(); used[i]=false; } } vector<vector<int>> permute(vector<int>& nums){ vector<vector<int>> result; vector<int> path; vector<bool> used(nums.size(), false); backtracking(nums, used, path, result); return result; } //不易理解 vector<vector<int>> permute(vector<int>& nums){ vector<vector<int>> ans; backtracking(nums, 0, ans); return ans; } void bactracking(vector<int>& nums, int level, vector<vector<int>>& ans){ if(level = nums.size()-1){ ans.push_back(nums); return; } for(int i=level; i<nums.size(); i++){ swap(nums[i], nums[level]); bactracking(nums, level+1, ans); swap(nums[i], nums[level]); } } //47.全排列II vector<vector<int>> permuteUnique(vector<int>& nums){ vector<vector<int>> result; vector<int> path; vector<bool> used(nums.size(), false); sort(nums.begin(), nums.end()); backtracking(nums, used, path, result); return result; } void backtracking(vector<int>& nums, vector<bool>& used, vector<int>& path, vector<vector<int>>& result){ if(path.size()==nums.size()){ result.push_back(path); return; } for(int i=0; i<nums.size(); i++){ if(used[i]==true) continue; //剪枝去重 used[i-1]==false 之前的重复的回溯了 if(i>0 && nums[i]==nums[i-1] && used[i-1]==false) continue; path.push_back(nums[i]); used[i]=true; backtracking(nums, used, path, result); path.pop_back(); used[i]=false; } } //20.有效的括号 栈 bool isValid(stirng s){ stack<char> stk; for(int i=0; i<s.size(); i++){ if(s[i]=='{' || s[i]=='[' || s[i]=='('){ stk.push(s[i]); }else{ if(stk.empty()) return false; char c=stk.top(); if((c=='{'&& s[i]=='}') || (c=='[' && s[i]==']') || (c=='(' && s[i]==')')){ stk.pop(); }else{ return false; } } } return stk.empty(); } //剑指offer03.数组中重复的数字 哈希 int findRepeatNumber(vector<int>& nums){ unordered_set<int> hash; for(int i=0; i<nums.size(); i++){ if(hash.count(nums[i])){ return nums[i]; } else{ hash.insert(nums[i]); } } return -1; } //21.合并两个有序链表 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2){ ListNode* head=new ListNode(-1); ListNode* h=head; while(l1 && l2){ if(l1->val > l2->val){ h->next=l2; l2=l2->next; }else{ h->next=l1; l1=l1->next; } h=h->next; } h->next=l1? l1:l2; return head->next; } //4.寻找两个正序数组的中位数 //中位数的定义:如果某个有序数组长度是奇数,那么中位数就是中间那个,如果是偶数,那么就是中间两个数的平均值 double findMedianSortArrays(vector<int> nums1, vector<int> nums2){ vector<int> nums; for(n:nums1) nums.push_back(n); for(n:nums2) nums.push_back(n); sort(nums.begin(), nums.end()); return double(nums.size()%2 ? nums[nums.size()/2]:(nums[nums.size()/2]+nums[nums.size()/2-1])/2.0); } //二分查找 double findMedianSortedArrays(vector<int> nums1, vector<int> nums2){ //二分查找 int sum=nums1.size()+nums2.size(); int n1=0, n2=0, val1=0, val2=0; while(n1+n2 <= sum/2) { val1=val2; if(n1==nums1.size()){ val2=nums2[n2++]; continue; } if(n2==nums2.size()){ val2=nums1[n1++]; continue; } if(nums1[n1]<nums2[n2]){ val2=nums1[n1++]; }else{ val2=nums2[n2++]; } } return sum%2 ? val2:(val1+val2)/2.0; } //45.跳跃游戏 贪心算法 int jump(vector<int>& nums){ int step=0; int end=0; int maxPos=0; for(int i=0; i<nums.size()-1; i++){ maxPos=max(nums[i]+i, maxPos); if(i == end){ //到达跳跃终点,再跳个最远的 end = maxPos; step++; } } return step; } //9.回文数 反转这个整数,如果相等就是回文数 bool isPalindrome(int x){ if(x<0) return false; if(x==0) return true; int y=x; long rev=0; while(x){ rev=rev*10+x%10; x=x/10; } return int(rev)==y; } //92.反转链表2 ListNode* reverseBetween(ListNode* head, int left, int right){ //设置dummyNode 是这一类问题的一般做法 ListNode *dummyNode = new ListNode(-1); dummyNode->next = head; ListNode *pre = dummyNode; //1.遍历至第一个节点 for(int i=0; i<left-1; i++){ pre=pre->next; } //2.反转链表 ListNode *cur =pre->next; ListNode * prev=nullptr, *next; for(int i=0;i<=right-left; i++){ next=cur->next; cur->next=prev; prev=cur; cur=next; } //3.修改left和right位置出节点的指向 pre->next->next=cur; pre->next=prev; return dummyNode->next; } //42.接雨水 int trap(vector<int>& height){ int n=height.size(); vector<int> left(n), right(n); for(int i=1; i<n; i++){ left[i]=max(left[i-1], height[i-1]); } for(int i=n-2; i>=0; i--){ right[i]=max(right[i+1],heght[i+1]); } int water=0; for(int i=0; i<n; i++){ int level=min(left[i], right[i]); water+=max(0, level-height[i]); } return water; } //53.最大子序和 贪心算法 int maxSubArry(vector<int>& nums){ int pre=0, maxAns=nums[0]; for(int i=0; i<nums.size(); i++){ pre=max(pre+nums[i], nums[i]); maxAns=max(maxAns, pre); } return maxAns; } //14.最长公共前缀 暴力 纵向扫描 string longestCommonPrefix(vector<string>& strs){ if(!strs.size()) return ""; int length = strs[0].size(); int count = str.size(); for(int i=0; i<length; i++){ char c=strs[0][i]; for(int j=0; j<count;j++){ if(i==strs[j].size() || c!=strs[j][i]){ return strs[i].substr(0,i); } } } return strs[0]; } //143.重排链表 快慢指针、反转链表、合并链表 void reorderList(ListNode* head){ if(head == nullptr){ return; } //寻找链表的中间节点 快慢指针方法 ListNode* mid=findmidnode(head); //反转后面的链表 ListNode* relist=reverselist(mid->next); //归并合并两个链表 mid->next=nullptr; mergelist(head,relist); } ListNode* findmidnode(ListNode* head){ ListNode* slow=head, *fast=head; while(fast->next!=nullptr && fast->next->next!=nullptr){ slow=slow->next; fast=fast->next->next; } return slow; } ListNode* reverselist(ListNode* head){ ListNode* prev=nullptr,* next; while(head){ next=head->next; head->next=prev; prev=head; head=next; } return prev; } void mergelist(ListNode* head, ListNode* relist){ ListNode *h=head,*tmp_h,*tmp_r; while(h && relist){ tmp_h=h->next; tmp_r=relist->next; h->next=relist; h=tmp_h; relist->next=h; relist=tmp_r; } } //146.LRU缓存机制 数据库设计 链表和哈希表都是很快的数据结构 //主要考察 哈希表+双向链表(list)组合体 设计一个缓存机制 class LRUCache{ private: list<pair<int, int>> cache; //双向链表,链表的尾节点是最近最少使用的数据节点 unordered_map<int, list<pair<int, int>>::iterator> key2node; //为什么用iterator迭代器(减少存储),list.erase()要传迭代器(指针的值)进去 int cap; //最大容量 public: LRUCache(int capacity):cap(capacity) {} int get(int key){ if(key2node.find(key)==key2node.end()){ return -1; } pair<int, int> node = *key2node[key]; cache.erase(key2node[key]); //将节点移动到链表头部并更新 cache.push_front(node); key2node[key]=cache.begin(); return node.second; } void put(int key, int val){ auto newNode = std::make_pair(key, val); if(key2node.count(key)){ //若节点已存在,则删除旧的节点 cache.erase(key2node[key]); }else{ if(cap == cache.size()){ key2node.erase(cache.back().first); //删除链表最后一个数据索引 cache.pop_back(); //删除链表最后一个数据 } } cache.push_front(newNode); key2node[key]=cache.begin(); //cache.begin()是一个指针 } }; //72.编辑距离 动态规划 int minDistance(string word1, string word2){ vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1, 0)); for(int i=0; i<dp.size(); i++){ dp[i][0]=i; } for(int j=0; j<dp[0].size(); j++){ dp[0][j]=j; } for(int i=1; i<dp.size(); i++){ for(int j=1; j<dp[i].size(); j++){ dp[i][j]=min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))+1; if(word1[i-1] == word2[j-1]){ dp[i][j]=min(dp[i-1][j-1], dp[i][j]); } } } return dp.back().back(); } //剑指offer22.链表中倒数第k个节点 快慢指针 ListNode* getKthFromEnd(ListNode* head, int k){ ListNode *fast=head,*slow=head; for(int i=0;i<k;i++){ fast=fast->next; } while(fast){ fast=fast->next; slow=slow->next; } return slow; } //25.K个一组翻转链表 hard ListNode* reverseKGroup(ListNode* head, int k){ ListNode* dummy = new ListNode(-1), *prev=nullptr,*next; dummy->next=head; int length=0; while(head!=nullptr){ length++; head=head->next; } for(int i=0;i<length/k; i++){ for(int j=0; i<k-1; j++){ next=head->next; head->next=prev; prev=head; head=next; } //连接链表 prev=cur; cur=prev->next; } return dummy->next; } //54.螺旋矩阵 vector<int> spiralOrder(vector<vector<int>>& matrix){ vector<int> ans; if(matrix.empty()) return ans; int u=0; //赋值上下左右的边界 int d=matrix.size()-1; int l=0; int r=matrix[0].size()-1; while(true){ for(int i=l; i<=r; i++) ans.push_back(matrix[u][i]); if(++u > d) break; for(int i=u; i<=d; i++) ans.push_back(matrix[i][r]); if(--r < l) break; for(int i=r; i>=l; i--) ans.push_back(matrix[d][i]); if(--d < u) break; for(int i=d; i>=u; i--) ans.push_back(matrix[i][l]); if(++l > r) break; } return ans; } //415.字符串相加 string addStrings(string num1, string num2){ int l1=nums1.size()-1, l2=num2.size()-1, carry=0; string str; while(l1>=0 || l2>=0 || carry!=0){ int x= l1>=0? num1[l1]-'0':0; int y= l2>=0? num2[l2]-'0':0; int sum=x+y+carry; carry=sum/10; str.push_back('0'+sum%10); l1--; l2--; } //翻转字符串 reverse(str.begin(), str.end()); return str; } //31.下一个排列 模拟 void nextPermutation(vector<int>& nums){ int n=nums.size(); for(i=n-1; i>=0; i--){ if(i==0){ sort(nums.begin(), nums.end()); return; }else{ if(nums[i]>nums[i-1]){ sort(nums.begin()+i, nums.end()); for(int j=i, j<n; j++){ if(nums[j]>nums[i-1]){ swap(nums[j], nums[i-1]); return; } } } } } } //200.岛屿数量 int numIslands(vector<char>& grid){ int numlands=0; for(int i=0; i<grid.size();j++){ for(int j=0;j<grid[i].size();j++){ if(grid[i][j]=='1'){ numlands++; dfs(grid, i,j); } } } } void dfs(vector<char>& grid, int i, int j){ grid[i][j]='0'; if(i-1>=0 && grid[i-1][j]=='1') dfs(grid, i-1,j); if(j-1>=0 && grid[i][j-1]=='1') dfs(grid, i, j-1); if(i+1<grid.size() && grid[i+1][j]=='1') dfs(grid, i+1, j); if(j+1<grid[0].size() && grid[i][j+1]=='1') dfs(grid, i, j+1); } //82.删除排序链表中的重复元素II ListNode* deleteDuplicates(ListNode* head){ if(!head || !head->next) return head; ListNode* dummy=new ListNode(-1); dummy->next=head; ListNode* pre=dummy; ListNode* cur=head; while(cur){ //跳过当前的重复节点,使得cur指向当前重复元素的最后一个位置 while(cur->next && cur->val=cur->next->val){ cur=cur->next; } if(pre->next=cur){ //pre和cur之间没有重复节点,pre后移 pre=pre->next; }else{ //pre->next指向cur的下一个位置(相当于跳过了当前的重复元素) //但是pre不移动,仍然指向已遍历的链表结尾 pre->next=cur->next; } cur=cur->next; } return dummy->next; } //递归 ListNode* deleteDuplicates(ListNode* head){ if(!head || !head->next) return head; if(head->val !=head->next->val){ head->next=deleteDuplicates(head->next); }else{ ListNode* move=head->next; while(move && head->val==move->val){ move=move->next; } return deleteDuplicates(move); } return head; } //131.分割回文串 回溯 class Solution{ private: vector<vector<string>> result; vector<string> path; //放已经回文的子串 void bactracking(const string & s, int startIndex){ //如果起始位置已经大于s的大小,说明已经找到了一组分割方案了 if(startIndex >= s.size()){ result.push_back(path); return; } for(int i=startIndex; i<s.size(); i++){ if(isPalindrome(s, startIndex, i)){ //是回文子串 //获取[startIndex, i]在s中的子串 string str=s.substr(startIndex, i-startIndex+1); path.push_back(str); }else{ continue; } backtracking(s, i+1); //寻找i+1为起始位置的子串 path.pop_back(); //回溯过程,弹出本次已经添加的子串 } } bool isPalindrome(const string& s, int start, int end){ for(int i=start, j=end; i<j; i++,j--){ if(s[i] != s[j]){ return false; } } return true; } public: vector<vector<string>> partition(stirng s){ result.clear(); path.clear(); backtracking(s, 0); return result; } } //121.买卖股票最佳时机 int naxProfit(vector<int>& prices){ int minprice=prices[0], maxprofit=0; for(int i=1; i<prices.size(); i++){ minprice=min(minprice, prices[i]); maxprofit=max(maxprofit, prices[i]-minprice); } return maxprofit; } //19.删除链表的倒数第N个结点 ListNode* removeNthFromEnd(ListNode* head, int n){ ListNode* slow=head, *fast=head; if(head==nullptr) return head; while(n>0){ n--; fast=fast->next; } if(fast==nullptr) return head->next; while(fast->next){ slow=slow->next; fast=fast->next; } ListNode *del=slow->next; slow->next=slow->next->next; delete del; return head; } //11.盛最多水的容器 双指针 int maxArea(vector<int>& height){ int l=0,r=height.size()-1, maxArea=0; while(l<r){ maxArea=max(maxArea,min(height[l],height[r])*(r-l)); if(height[l]>height[r]){ r--; }else{ l++; } } return maxArea; } //22.括号生成 vector<string> generateParenthesis(int n){ vector<string> ans; dfs(ans, "", 0, 0, n); return ans; } void dfs(vector<string>& ans, string str, int l, int r, int n){ if(l>n || r>n || l<r){ return; } if(l==n && r==n){ ans.push_back(str); return; } dfs(ans, str+'(', l+1, r, n); dfs(ans, str+')', l, r+1, n); } //10.正则表达式匹配 bool isMatch(string s, string p){ if(p.empty()) return s.empty(); auto first_match= !s.empty() && (s[0]==p[0] || p[0]=='.'); if(p.length()>=2 && p[1]=='*'){ return isMatch(s, p.substr(2)) || (first_match && isMatch(s.substr(1),p)); }else{ return first_match && isMatch(s.substr(1), p.substr(1)); } } //剑指offer09.用两个栈实现队列 class CQueue{ private: stack<int> stk1,stk2; public: CQueue(){} void appendTail(int value){ stk1.push(value); } int deleteHead(){ if(stk2.empty()){ while(!stk1.empty()){ stk2.push(stk1.top()); stk1.pop(); } } if(stk2.empty()){ return -1; }else{ int ret=stk2.top(); stk2.pop(); return ret; } } } //739.每日温度 单调递减栈 //单调栈:通过维持栈内值的递增(递减)性,在整体O(n)的时间内处理需要大小比较的问题。 /*题解:我们维持一个单调递减的栈,表示每天的温度;为了方便计算天数差,我们这里存放位置(即日期)而非温度本身。我们从左向右遍历温度数组,对于每个日期p, 如果p的温度比栈顶存储位置q的温度高,则我们取出q,并记录q需要等待的天数为p-q;我们重复这一过程,直到p的温度小于等于栈顶存储位置的温度(或栈空)时,我们将p 插入栈顶,然后考虑下一天。 */ vector<int> dailyTemperatures(vector<int>& T){ int n=T.size(); vector<int> ans(n); stack<int> indices; for(int i=0; i<n;i++){ while(!indices.empty()){ int pre_index=indices.top(); if(T[i] <= T[pre_index]){ break; } indices.pop(); ans[pre_index]=i-pre_index; } indices.push(i); } } //剑指Offer42.连续子数组的最大和 int maxSubArray(vector<int>& nums){ int sum=0,maxsum=nums[0]; for(int i=0; i<nums.size(); i++){ sum=max(sum+nums[i], nums[i]); maxsum=(maxsum, sum); } return maxsum; } //103.二叉树的锯齿形层序遍历 二叉树层序遍历想到队列解决 queue vector<vector<int>> zigzagLevelOrder(TreeNode* root){ vector<vector<int>> res; queue<TreeNode *> q; if(root) q.push(root); bool lr=true; while(!q.empty()){ int size=q.size(); vector<int> level(size, 0); //存储一层的元素 while(size--){ TreeNode* node = q.front(); q.pop(); level[lr? level.size()-size-1:size]=rool->val; if(node->left) q.push(node->left); if(node->right) q.push(node->right); } res.push_back(level); lr=!lr; } return res; } //105.从前序与中序遍历序列构造二叉树 class Solution{ private: unordered_map<int, int> index; public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder){ int n=preorder.size(); for(int i=0; i<n; i++){ index[inorder[i]]=i; } return myBuildTree(preorder, inorder, 0, n-1, 0, n-1); } //递归函数 TreeNode* myBuildTree(const vector<int>& preorder, const vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right){ if(preorder_left > preorder_right){ return nullptr; } //前序遍历中第一个节点就是根节点 int preorder_root=preorder_left; //在中序遍历中定位根节点 int inorder_root = index[preorder[preorder_root]]; //先把根节点简历出来 TreeNode* root=new TreeNode(preorder[preorder_root]); //得到左子树的节点数目 int size_left_subtree=inorder_root-inorder_left; //递归的构造左子树,并连接到根节点 root->left=myBuildTree(preorder, inorder, preorder_left+1, preorder_left+size_left_subtree, inorder_left, inorder_root-1); //递归的构造右子树,并连接到根节点 root->right = myBuildTree(preorder, inorder, preorder_left+size_left_subtree+1, preorder_right, inorder_root+1, inorder_right); return root; } } //1190.反转每对括号间的子串 stack string reverseparentheses(string s){ string res; stack<string> stk; for(char c:s){ if(c=='('){ stk.push(res); res=""; }else if(c==')'){ reverse(res.begin(), res.end()); res=stk.top()+res; stk.pop(); }else{ res.push_back(c); } } return res; } //56.合并区间 排序+双指针 vector<vector<int>> merge(vector<vector<int>>& intervals){ sort(intervals.begin(), intervals.end()); vector<vector<int>> res; int l=0,r=0,n=intervals.size(); for(int i=0; i<n; i++){ l=intervals[i][0]; r=intervals[i][1]; while(i<n-1 && r>=intervals[i+1][0]){ r=max(r,intervals[i+1][1]); i++; } res.push_back({l, r}); } return res; } //剑指Offer25.合并两个排序的链表 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2){ ListNode* dummy=new ListNode(-1), *head=dummy; while(l1 && l2){ if(l1->val < l2->val){ head->next=l1; l1=l1->next; }else{ head->next=l2; l2=l2->next; } head=head->next; } head->next=l1? l1:l2; return dummy->next; } //135.分发糖果 int candy(vector<int>& ratings){ int size=ratings.size(); if(size<2) return size; vector<int> nums(size, 1); //从左向右遍历 for(int i=1; i<size; i++){ if(ratings[i] > rating[i-1]){ nums[i]=nums[i-1]+1; } } //从右往左遍历 for(int i=size-2; i>=0; i--){ if(ratings[i]>ratings[i+1]){ nums[i]=max(nums[1],nums[i+1]+1); } } return accumulate(nums.begin(), nums.end(), 0); } //118.杨辉三角 找规律,模拟 vector<vector<int>> generate(int numRows){ vector<vector<int>> ans(numsRows); if(numsRows == 0) return ans; //若numRows为空,返回空数组; for(int i=0; i<numRows; i++){ //给数组一个个的赋值 for(int j=0; j<=i; j++){ if(j==0 || j==i){ //若是两边的边界,赋值为1 ans[i].push_back(1); }else{ ans[i].push_back(ans[i-1][j-1]+ans[i-1][j]); //否则赋值为左上和右上的和 } } } return ans; } //136.只出现一次的数字 ^ int singleNumber(vector<int>& nums){ int ans=0; for(int num:nums){ ans^=num; } return ans; } //48.旋转图像 void rotate(vector<vector<int>>& matrix){ int temp=0, n=matrix.size()-1; for(int i=0; i<=n/2;i++){ for(int j=i;j<n-i;j++){ temp=matrix[j][n-i]; matrix[j][n-i]=matrix[i][j]; matrix[i][j]=matrix[n-j][i]; matrix[n-j][i]=matrix[n-i][n-j]; matrix[n-i][n-j]=temp; } } } //16.最接近的三数之和 排序+双指针 int threeSumClosest(vector<int>& nums, int target){ sort(nums.begin(), nums.end()); int closeSum=nums[0]+nums[1]+nums[2]; for(int i=0; i<nums.size(); i++){ int l=i+1,r=nums.size()-1; while(l<r){ int sum=nums[i]+nums[l]+nums[r]; if(abs(target-closeSum) > abs(target-sum)){ closeSum=sum; } if(sum>target){ r--; }else if(sum<target){ l++; }else{ return sum; } } } return closeSum; } //剑指Offer29.顺时针打印矩阵 vector<int> spiralOrder(vector<vector<int>>& matrix){ vector<int> ret; if(matrix.empty()) return ret; int l=0; //左边界 int r=matrix[0].size()-1; //右边界 int u=0; //上边界 int d=matrix.size()-1; //下边界 while(1){ for(int i=l; i<=r; i++) ret.push_back(matrix[u][i]); if(++u>d) break; for(int i=u; i<=d; i++) ret.push_back(matrix[i][r]); if(--r<l) break; for(int i=r; i>=l; i--) ret.push_back(matrix[d][i]); if(--d<u) break; for(int i=d; i>=u; i--) ret.push_back(matrix[i][l]); if(++l>r) break; } return ret; }
//6.Z字形变换 string convert(string s, int numRows){ if(numRows == 1) return s; vector<string> rows(min(numRows, int(s.size()))); int curRow = 0; bool goingDown = false; for(char c:s){ rows[curRow] += c; if(curRow == 0 || curRow == numRows-1) goingDown=!goingDown; curRow += goingDown? 1:-1; } string ret; for(string row:rows) ret+=row; return ret; } //102.二叉树的层序遍历 queue vector<vector<int>> levelOrder(TreeNode* root){ vector<vector<int>> ans; queue<TreeNode*> q; if(!root) return ans; q.push(root); while(q){ int size=q.size(); vector<int> level; while(size>0){ size--; TreeNode* node=q.front(); q.pop(); level.push_back(node->val); if(node->left) q.push(node->left); if(node->right) q.push(node->right); } ans.push_back(level); } return ans; } //215.数组中的第K大个元素 priority_queue优先队列,最大值先出数据结构 int findKthLargest(vector<int>& nums, int k){ priority_queue<int> priq; //优先队列,最大值先出数据结构 int t=nums.size()-k+1; for(int num:nums){ priq.push(num); if(priq.size()>t) priq.pop(); } return priq.top();
}
//322.零钱兑换 动态规划
int coinChange(vector<int>& coins, int amount){ int Max=amount+1; vector<int> dp(amount+1, Max); dp[0]=0; for(int i=1; i<=amount; ++i){ for(int j=0; j< coins.size(); ++j){ if(coins[j]<=i){ dp[i]=min(dp[i], dp[i-coins[j]]+1); } } } return dp[amount]>amount ? -1:dp[amount]; }
//283.移动零 双指针 void moveZeroes(vector<int>& nums){ if(!nums.size()) return; int j=0; for(int i=0; i<nums.size(); i++){ if(nums[i]!=0){ nums[j++]=nums[i]; } } for(int i=j; i<nums.size();i++){ nums[i]=0; } } //23.合并K个升序链表 递归+合并两个有序数组 ListNode* mergeKLists(vector<ListNode*> lists){ if(lists.empty()) return nullptr; ListNode* ans=lists[0]; for(int i=1; i<lists.size(); i++){ ans=mergeLists(ans, lists[i]); } return ans; } ListNode* mergeLists(ListNode* l1, ListNode* l2){ ListNode* dummy=new ListNode(-1), *head=dummy; while(l1 && l2){ if(l1->val < l2->val){ head->next=l1; l1=l1->next; }else{ head->next=l2; l2=l2->next; } head=head->next; } head->next=l1? l1:l2; return dummy->next; } //69.x的平方根 二分查找 边界问题 int mySqrt(int a){ int l=0,r=a, ans=-1; while(l<=r){ int mid=(l+r)/2; if((long long)mid*mid <= a){ ans=mid; l=mid+1; }else{ r=mid-1; } } return ans; } //141.环形链表 bool hasCycle(ListNode* head){ unordered_set<ListNode*> hash; while(head){ if(hash.count(head)) return true; hash.insert(head); head=head->next; } return false; } //剑指Offer07.重建二叉树 已知前序中序重建二叉树 unorder_map<int, int> index; TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder){ int n=preorder.size(); for(int i=0; i<n; i++){ index[inorder[i]]=i; } return myBuildTree(preorder, inorder,0, n-1, 0, n-1); } //递归函数 TreeNode* myBuildTree(const vector<int>& preorder, const vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right){ if(pre_left> preright) return nullptr; //前序遍历中第一个节点就是根节点 int preorder_root=preorder_left; //在中序遍历中定为根节点 int inorder_root=index[preorder[preorder_root]]; //先把根节点建立出来 TreeNode* root=new TreeNode(preorder[preorder_root]); //得到左子树的节点数目 int size_left_subtree=inorder_root-inorder_left; //递归的构造左子树并连接到根节点 root->left=myBuildTree(preorder, inorder, preorder_left+1, preorder_left+size_left_subtree, inorder_left, inorder_root-1); //递归的构造右子树并连接到根节点 root->right=myBuildTree(preorder, inorder, preorder_left+size_left_subtree+1, preorder_right, inorder_root+1, inorder_right); return root; } //509.斐波那契数列 int fib(int n){ if(n<2) return n; int p=0,q=0,r=1; for(int i=2; i<=n; i++){ p=q; q=r; r=p+q; } return r; } //134.加油站 贪心算法 int canCompleteCircuit(vector<int>& gas, vector<int>& cost){ int curSum=0; int totalSum=0; int start=0; for(int i=0; i<gas.size(); i++){ curSum += gas[i]-cost[i]; totalSum+=gas[i]-cost[i]; if(curSum<0){ //当前累加curSum一旦小于0 start=i+1; //起始位置更新为i+1 curSum=0; } } if(totalSum<0) return -1; //说明怎么走都不可能跑完一圈 return start; } //32.最长有效括号 动态规划解决比较好 int longestVaildParentheses(string s){ int maxans=0; stack<int> stk; stk.push(-1); for(int i=0; i<s.length();i++){ if(s[i]=='('){ stk.push(i); }else{ stk.pop(); if(stk.empty()){ stk.push(i); }else{ maxans=max(maxans, i-stk.top()); } } } return maxans; } //13.罗马数字转整数 int romanToInt(string s){ int result=0; map<char, int> luomab={ {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000} };//初始化哈希表 for(int i=0; i<s.size(); i++){ if(luomab[s[i]]<luomab[s[i+1]]){ //s[n]=0; result-=luomab[s[i]]; }else{ result+=luomab[s[i]]; } } return result; } //41.缺失的第一个正数 int firstMissingPositive(vector<int>& nums){ unordered_set<int> hash; for(int num:nums){ if(!hash.count(num)) hash.insert(num); } for(int i=1; i<=nums.size();i++){ if(!hash.count(i)) return i; } return nums.size()+1; } //76.最小覆盖子串 滑动窗口 hard 比较有用 string minWindow(string s, string t){ unordered_map<char, int> map; for(char c:t) map[c]++; int left=0,cnt=0,minlen=s.size()+1,start=left; for(int i=0; i<s.size(); i++){ if(--map[s[i]] >= 0) ++cnt; while(cnt == t.size()){ if(minlen > i-left+1){ minlen=i-left+1; start=left; } if(++map[s[left]] > 0) cnt--; //如果s[left]不在t里边,就是map[s[left]]就是负的,因为前边--了 left++; } } return minlen==s.size()+1 ? "":s.substr(start, minlen); } //199.二叉树的右视图 使用层序遍历,并只保存最后一个节点的值 vector<int> rightSideView(TreeNode* root){ vector<int> res; queue<TreeNode*> q; if(!root) return res; q.push(root); while(!q.empty()){ int size=q.size(); res.push_back(q.back()->val); while (size--){ TreeNode* node=q.front(); q.pop(); if(node->left) q.push(node->left); if(node->right) q.push(node->right); } } return res; } //83.删除排序链表中的重复元素 ListNode* deleteDuplicates(ListNode* head){ ListNode* h=head; while(h && h->next){ if(h->val == h->next->val){ h->next=h->next->next; }else{ h=h->next; } } return head; } //867.转置矩阵 vector<vector<int>> transpose(vector<vector<int>>& matrix){ int m=matrix.size(), n=matrix[0].size(); vector<vector<int>> transposed(n, vector<int>(m,0)); for(int i=0; i<m;i++){ for(int j=0; j<n;j++){ transposed[j][i]=matrix[i][j]; } } return transposed; }
//394.字符串解码 stack 比较实用 string decodeString(string s){ stack<int> numStack; stack<string> resStack; int num = 0; string res; for(int i=0; i<s.size(); i++){ if(isalpha(s[i])){ res.push_back(s[i]); }else if(isdigit(s[i])){ num=num*10+s[i]-'0'; } else if(s[i] == '['){ resStack.push(res); res=""; numStack.push(num); num=0; }else{ for(int j=0; j<numStack.top(); j++){ resStack.top()+=res; } numStack.pop(); res=resStack.top(); resStack.pop(); } } return res; } //面试题02.05.链表求和 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2){ ListNode* dummy=new ListNode(-1),*head=dummy; int carry=0,sum=0; while(l1 || l2){ sum=carry; if(l1 != nullptr){ sum+=l1->val; l1=l1->next; } if(l2 != nullptr){ sum+=l2->val; l2=l2->next; } head->next=new ListNode(sum%10); head=head->next; carry=sum/10; } if(carry) head->next=new ListNode(carry); return dummy->next; } //55.跳跃游戏 bool canJump(vector<int>& nums){ int k=0; for(int i=0; i<nums.size(); i++){ if(k<i) return false; k=max(k, i+nums[i]); } return ture; } //59.螺旋矩阵 上下左右边界要分清楚 模拟法 vector<vector<int>> generateMatrix(int n){ int l=0, r=n-1, t=0, b=n-1; vector<vector<int>> matrix(n, vector<int>(n,0)); int num=1, target=n*n; while(num<=target){ for(int i=l; i<=r; i++) matrix[t][i]=num++; t++; for(int i=t; i<=b; i++) matrix[i][r]=num++; r--; for(int i=r; i>=l; i--) matrix[b][i]=num++; b--; for(int i=b; i>=t; i--) matrix[i][l]=num++; l++; } return matrix; } //剑指Offer04.二维数组中的查找 二分查找 bool findNumberIn2DArray(vector<vector<int>>& matrix, int target){ int m=matrix.size(); if(m==0) return false; int n=matrix[0].size(); int i=0,j=n-1; while (i<m && j>=0){ if(matrix[i][j] == target){ return true; }else if(matrix[i][j] < target){ i++; }else{ j--; } } return false; } //18.四数之和 三数之和 排序+双指针 vector<vector<int>> fourSum(vector<int>& nums, int target){ sort(nums.begin(), nums.end()); vector<vector<int>> res; if(nums.size()<4) return res; int a,b,c,d,n=nums.size(); for(a=0;a<=n-4;a++){ if(a>0 && nums[a]==nums[a-1]) continue; //确保nums[a]改变了 for(b=a+1;n<=n-3;b++){ if(b>a+1 && nums[b]==nums[b-1]) continue; //确保nums[b]改变了 c=b+1;d=n-1; while(c<d){ if(nums[a]+nums[b]+nums[c]+nums[d]<target){ c++; }else if(nums[a]+nums[b]+nums[c]+nums[d]>target){ d--; }else{ res.push_back({nums[a], nums[b], nums[c], nums[d]}); while(c<d && nums[c+1]==nums[c]){ //确保c变了 c++; } while(c<d && nums[d-1]==nums[d]){ //确保d变了 d--; } c++; d--; } } } } return res; } //34.在排序数组中查找元素的第一个和最后一个位置 二分查找 vector<int> searchRange(vector<int>& nums, int target){ if(!nums.size()) return vector<int> {-1,-1}; int lower=lower_bound(nums, target); int upper=upper_bound(nums, target); if(lower==nums.size() || nums[lower]!=target) return vector<int>{-1,-1}; return vector<int>{lower, upper}; } int lower_bound(vector<int>& nums, int target){ int l=0,r=nums.size()-1,mid; while(l<=r){ int mid=l+(r-l)/2; if(nums[mid]==target){ r=mid-1; }else if(nums[mid]>target){ r=mid-1; }else{ l=mid+1; } } return l; } int upper_bound(vector<int>&nums, int target){ int l=0,r=nums.size()-1,mid; while(l<=r){ mid=l+(r-l)/2; if(nums[mid]==target){ l=mid+1; }else if(nums[mid]>target){ r=mid-1; }else{ l=mid+1; } } return r; } //1047.删除字符串中的所有相邻重复项 string removeDuplicates(string s){ string res; for(int i=0; i<s.size(); i++){ if(res.empty() || res.back()!=s[i]){ res.push_back(s[i]); }else{ res.pop_back(); } } return res; } //62.不同路径 动态规划 dp[i][j]=dp[i-1][j]+dp[i][j-1] int uniquePaths(int m, int n){ 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 i=1;i<m;i++){ for(int j=1;j<n;j++){ dp[i][j]=dp[i-1][j]+dp[i][j-1]; } } return dp[m-1][n-1]; } //704.二分查找 int search(vector<int>& nums, int target){ int l=0,r=nums.size()-1,mid; while(l<=r){ mid=l+(r-l)/2; if(nums[mid]==target){ return mid; }else if(nums[mid]>target){ r=mid-1; }else{ l=mid+1; } } return -1; } //剑指offer10-1.斐波那契数列 int fib(int n){ if(n<2) return n; int q=0,p=0,r=1; for(int i=0;i<=n;i++){ q=p; p=r; r=(q+p)%1000000007; } return r; } //221.最大正方形 动态规划 int maximalSquare(vector<vector<int>>& matrix){ if(matrix.size()==0 || matrix[0].size()==0){ return 0; } int m=matrix.size(),n=matrix[0].size(),max_side=0; vector<vector<int>> dp(m, vector<int>(n,0)); //dp数组 for(int i=0; i<m; i++){ for(int j=0; j<n; j++){ if(matrix[i][j]='1'){ if(i==0 || j==0){ //边界 dp[i][j]=1; }else{ dp[i][j]=min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))+1; } } max_side=max(max_side, dp[i][j]); } } return max_side*max_side; } //88.合并两个有序数组 双指针 void merge(vector<int>& nums1, int m, vector<int>& nums2, int n){ int k=m-- +n-- -1; while(m>=0 && n>=0){ if(nums1[m]>nums2[n]){ nums1[k--]=nums1[m--]; }else{ nums1[k--]=nums2[n--]; } } while(n>=0){ nums1[k--]=nums2[n--]; } } //198.打家劫舍 dp方程dp[i]=max(nums[i]+dp[i-2], dp[i-1]); int rob(vector<int>& nums){ int n=nums.size(); if(n==1) return nums[0]; vector<int> dp(n); dp[0]=nums[0]; dp[1]=max(nums[0], nums[1]); for(int i=2; i<n; i++){ dp[i]=max(nums[i]+dp[i-2], dp[i-1]); } return dp[n-1]; }
//剑指Offer52.两个链表的第一个公共节点 相交链表 ListNode* getIntersectionNode(ListNode *headA, ListNode* headB){ ListNode* node1=headA, *node2=headB; while(node1!=node2){ node1= node1==nullptr? headB:node1->next; node2= node2==nullptr? headA:node2->next; } return node1; } //剑指Offer06.从尾到头打印链表 vector<int> reversePrint(ListNode* head){ //栈 stack<int> stk; vector<int> res; while(head){ stk.push(head->val); head=head->next; } while(stk.size()){ vec.push_back(stk.top()); stk.pop(); } return res; } //剑指Offer10-II.青蛙跳台阶问题 动态规划 斐波那契数列 dp[i]=dp[i-1]+dp[i-2]; int numWays(int n){ if(n==0) return 1; vector<int> dp(n+1,0); dp[0]=1; dp[1]=1; for(int i=2;i<=n;i++){ dp[i]=(dp[i-1]+dp[i-2])%100000007; } return dp[n]; } //剑指Offer11.旋转数组的最小数字 二分查找 int minArray(vector<int>& numbers){ int l=0, r=numbers.size()-1; while(l<r){ int mid=(l+r)/2; if(numbers[mid]>numbers[r]) l=mid+1; else if(numbers[mid]<numbers[r]) r=mid; else r--; } return numbers[l]; } //234.回文链表 stack bool isPalindrome(ListNode* head){ stack<int> stk; ListNode* p=head; while(p){ stk.push(p->val); p=p->next; } while(!stk.empty()){ if(stk.top()==head->val){ stk.pop(); head=head->next; }else{ return false; } } return true; } //104.二叉树的最大深度 递归 int maxDepth(TreeNode* root){ if(!root) return 0; int left=1+maxDepth(root->left); int right=1+maxDepth(root->right); return left>right? left:right; } //剑指Offer40.最小的k个数 快排 vector<int> getLeastNumbers(vector<int>& arr, int k){ quickSort(arr, 0, arr.size()-1); vector<int> res; res.assign(arr.begin(), arr.begin()+k); return res; } void quickSort(vector<int>& arr, int l, int r){ //子数组长度为1时终止递归 if(l>=r) return; int first=l, last=r, key=arr[first]; while(first<last){ //循环完会把arr分成两部分,左边小于key的值,右边大于 key的值 while(first<last && key<=arr[last]){ last--; } arr[first]=arr[last]; while(first<last && key>=arr[first]){ first++; } arr[last]=arr[first]; } arr[first]=key; qucikSort(arr, l, first); qucikSort(arr, first+1, r); } //64.最小的路径和 动态规划 int minPathSum(vector<vector<int>>& grid){ int m=grid.size(), n=grid[0].size(); vector<vector<int>> dp(m, vector<int>(n,0)); for(int i=0; i<m; i++){ for(int j=0; j<n; j++){ if(i==0 && j==0){ dp[i][j]=grid[i][j]; }else if(i==0){ dp[i][j]=dp[i][j-1]+grid[i][j]; }else if(j==0){ dp[i][j]=dp[i-1][j]+dp[i][j]; }else{ dp[i][j]=min(dp[i-1][j], dp[i][j-1])+dp[i][j]; } } } return dp[m-1][n-1]; } //347.前k个高频元素 vector<int> topKFrequent(vector<int>& nums, int k){ unordered_map<int, int> counts; int max_count=0; for(const int &num:nums){ max_count=max(max_count, ++counts[num]); //map统计频次,找出最大的频次 } vector<vector<int>> buckets(max_count+1); for(auto p:counts){ buckets[p.second].push_back(p.first); } vector<int> ans; for(int i=max_count; i>=0 && ans.size()<k; --i){ for(int num:buckets[i]){ ans.push_back(num); if(ans.size() == k){ break; } } } return ans; } //面试题01.01.判断字符是否唯一 bool isUnique(string astr){ unordered_set<char> hash; for(char c:astr){ if(hash.count(c)){ return false; }else{ hash.insert(c); } } return true; } //面试题02.03.删除中间节点 void deleteNode(ListNode* node){ node->val=node->next->val; node->next=node->next->next; } //33.搜索旋转排序数组 int search(vector<int>& nums, int target){ int l=0, r=nums.size()-1; while(l<=r){ int mid = (l+r)/2; if(nums[mid]==target) return mid; if(nums[mid]<nums[r]){ //右边是有序的 if(nums[mid]<target && target<=nums[r]){ l=mid+1; }else{ r=mid-1; } }else{ //左边是有序的 if(nums[mid]>target && target>=nums[l]){ r=mid-1; }else{ l=mid+1; } } } return -1; } //剑指Offer26.树的子结构 bool isSubStructure(TreeNode* A, TreeNode* B){ if(A==nullptr || B==nullptr) return false; return compare(A,B) || isSubStructure(A->left, B) || isSubStructure(A->right, B); } bool compare(TreeNode* A, TreeNode* B){ if(B==nullptr) return true; if(A==nullptr) return false; return (A->val == B->val) && compare(A->left, B->left) && compare(A->right, B->right); } //剑指Offer48.最长不包含重复字符的子字符串 int lengthOfLongestSubstring(string s){ if(s.size()==0) return 0; int maxStr=0; int left=0; unordered_set<char> lookup; for(int i=0; i<s.size(); i++){ while(lookup.find(s[i] != lookup.end())){ lookup.erase(s[left]); left++; } lookup.insert(s[i]); maxStr=max(maxStr, i-left+1); } return maxStr; } //349.两个数组的交集 vector<int> intersection(vector<int>& nums1, vector<int>& nums2){ //哈希 unordered_set<int> hash(nums1.begin(), nums1.end()); unordered_set<int> hash1; vector<int> res; for(int num:nums2){ if(hash.find(num) != hash.end()){ if(hash1.find(num) == hash1.end()){ res.push_back(num); hash1.insert(num); } } } return res; } //面试题01.06字符串压缩 string compressString(string s){ int cnt=1; string res; for(int i=0; i<s.size(); i++){ res+=s[i]; while(s[i]==s[i+1]){ cnt++; i++; } res+=tostring(cnt); cnt=1; } return res.size()>=s.size()? s:res; } //35.搜索插入位置 二分查找 int searchInsert(vector<int>& nums, int target){ if(nums.size()==0) return 0; int l=0,r=nums.size()-1,mid; while(l<=r){ mid=(l+r)/2; if(nums[mid]==target){ return mid; }else if(nums[mid]>target){ r=mid-1; }else{ l=mid+1; } } return r; } //81.搜索旋转排序数组(数组中值可以重复) bool search(vector<int>& nums, int target) { int l=0,r=nums.size()-1; while(l<=r){ while(l<r && nums[l]==nums[l+1]) l++; //去重 while(l<r && nums[r]==nums[r-1]) r--; int mid=(l+r)/2; if(nums[mid]==target) return true; if(nums[mid]<nums[r]){ if(target>nums[mid] && target<=nums[r]){ l=mid+1; }else{ r=mid-1; } }else{ if(target>=nums[l] && target<nums[mid]){ r=mid-1; }else{ l=mid+1; } } } return false; } //90.子集II private: vector<vector<int>> result; vector<int> path; void backtracking(vector<int>& nums, int startIndex) { result.push_back(path); unordered_set<int> uset; for (int i = startIndex; i < nums.size(); i++) { if (uset.find(nums[i]) != uset.end()) { continue; } uset.insert(nums[i]); path.push_back(nums[i]); backtracking(nums, i + 1); path.pop_back(); } } public: vector<vector<int>> subsetsWithDup(vector<int>& nums) { result.clear(); path.clear(); sort(nums.begin(), nums.end()); // 去重需要排序 backtracking(nums, 0); return result; }