├── 1.Two Sum ├── 1.cpp └── README.md ├── 10.Regular Expression Matching ├── 10.cpp └── README.md ├── 101.Symmetric Tree ├── 101.cpp └── README.md ├── 102.Binary Tree Level Order Traversal ├── 102.cpp └── README.md ├── 103.Binary Tree Zigzag Level Order Traversal ├── 103.cpp └── README.md ├── 104.Maximum Depth of Binary Tree └── 104.cpp ├── 105.Construct Binary Tree from Preorder and Inorder Traversal ├── 105.cpp └── README.md ├── 108.Convert Sorted Array to Binary Search Tree ├── 108.cpp └── README.md ├── 109.Convert Sorted List to Binary Search Tree ├── 109.cpp └── README.md ├── 11.Container With Most Water ├── 11.cpp └── README.md ├── 116.Populating Next Right Pointers in Each Node ├── 116.cpp └── README.md ├── 118.Pascal's Triangle ├── 118.cpp └── README.md ├── 121.Best Time to Buy and Sell Stock ├── 121.cpp └── README.md ├── 122.Best Time to Buy and Sell Stock II ├── 122.cpp └── README.md ├── 124.Binary Tree Maximum Path Sum ├── 124.cpp └── README.md ├── 125.Valid Palindrome ├── 125.cpp └── README.md ├── 127.Word Ladder └── README.md ├── 128.Longest Consecutive Sequence ├── 128.cpp └── README.md ├── 13.Roman to Integer ├── 13.cpp └── README.md ├── 130.Surrounded Regions ├── 130.cpp └── README.md ├── 131.Palindrome Partitioning ├── 131.cpp └── README.md ├── 134.Gas Station └── 134.cpp ├── 136.Single Number ├── 136.cpp └── README.md ├── 137.Single Number II ├── 137.cpp └── README.md ├── 138.Copy List with Random Pointer ├── 138.cpp └── README.md ├── 139.Word Break ├── 139.cpp └── README.md ├── 14.Longest Common Prefix ├── 14.cpp └── README.md ├── 140.Word Break II ├── 140.cpp └── README.md ├── 141.Linked List Cycle ├── 141.cpp └── README.md ├── 146.LRU Cache ├── 146.cpp └── README.md ├── 148.Sort List ├── 148.cpp └── README.md ├── 149.Max Points on a Line ├── 149.cpp └── README.md ├── 15.3Sum ├── 15.cpp └── README.md ├── 150.Evaluate Reverse Polish Notation ├── 150.cpp └── README.md ├── 152.Maximum Product Subarray ├── 152.cpp └── README.md ├── 155.Min Stack ├── 155.cpp └── README.md ├── 160.Intersection of Two Linked Lists ├── 160.cpp └── README.md ├── 162.Find Peak Element ├── 162.cpp └── README.md ├── 166.Fraction to Recurring Decimal ├── 166.cpp └── README.md ├── 169.Majority Element ├── 169.cpp └── README.md ├── 17.Letter Combinations of a Phone Number └── README.md ├── 171.Excel Sheet Column Number ├── 171.cpp └── README.md ├── 172.Factorial Trailing Zeroes ├── 172.cpp └── README.md ├── 179.Largest Number ├── 179.cpp └── README.md ├── 189.Rotate Array ├── 189.cpp └── README.md ├── 19.Remove Nth Node From End of List ├── 19.cpp └── README.md ├── 190.Reverse Bits ├── 190.cpp └── README.md ├── 191.Number of 1 Bits ├── 191.cpp └── README.md ├── 198.House Robber ├── 198.cpp └── README.md ├── 2.Add Two Numbers ├── 2.cpp └── README.md ├── 20.Valid Parentheses ├── 20.cpp └── README.md ├── 200.Number of Islands └── 200.cpp ├── 202.Happy Number ├── 202.cpp └── README.md ├── 203.Remove Linked List Elements ├── 203.cpp └── README.md ├── 204.Count Primes ├── 204.cpp └── README.md ├── 206.Reverse Linked List ├── 206.cpp └── README.md ├── 207.Course Schedule ├── 207.cpp └── README.md ├── 208.Implement Trie └── 208.cpp ├── 21.Merge Two Sorted Lists ├── 21.cpp └── README.md ├── 210.Course Schedule II ├── 210.cpp └── README.md ├── 212.Word Search II ├── 212.cpp └── README.md ├── 215.Kth Largest Element in an Array ├── 215.cpp └── README.md ├── 217.Contains Duplicate ├── 217.cpp └── README.md ├── 218.The Skyline Problem ├── 218.cpp └── README.md ├── 22.Generate Parentheses ├── 22.cpp └── README.md ├── 227.Basic Calculator II ├── 227.cpp └── README.md ├── 23.Merge k Sorted Lists ├── 23.cpp └── README.md ├── 230.Kth Smallest Element in a BST ├── 230.cpp └── README.md ├── 234.Palindrome Linked List ├── 234.cpp └── README.md ├── 236.Lowest Common Ancestor of a Binary Tree ├── 236.cpp └── README.md ├── 237.Delete Node in a Linked List ├── 237.cpp └── README.md ├── 238.Product of Array Except Self ├── 238.cpp └── README.md ├── 239.Sliding Window Maximum ├── 239.cpp └── README.md ├── 24.Swap Nodes in Pairs ├── 24.cpp └── README.md ├── 240.Search a 2D Matrix II ├── 240.cpp └── README.md ├── 242.Valid Anagram ├── 242.cpp └── README.md ├── 26.Remove Duplicates from Sorted Array ├── 26.cpp └── README.md ├── 268.Missing Number ├── 268.cpp └── README.md ├── 27.Remove Element ├── 27.cpp └── README.md ├── 279.Perfect Squares ├── 279.cpp └── README.md ├── 28.Implement strStr ├── 28.cpp └── README.md ├── 283.Move Zeroes ├── 283.cpp └── README.md ├── 287.Find the Duplicate Number ├── 287.cpp └── README.md ├── 289.Game of Life ├── 289.cpp └── README.md ├── 29.Divide Two Integers ├── 29.cpp └── README.md ├── 295.Find Median from Data Stream ├── 295.cpp └── README.md ├── 297.Serialize and Deserialize Binary Tree ├── 297.cpp └── README.md ├── 3.Longest Substring Without Repeating Characters ├── 3.cpp └── README.md ├── 300.Longest Increasing Subsequence ├── 300.cpp └── README.md ├── 31.Next Permutation ├── 31.cpp └── README.md ├── 315.Count of Smaller Numbers After Self ├── 315.cpp └── README.md ├── 322.Coin Change ├── 322.cpp └── README.md ├── 324.Wiggle Sort II ├── 324.cpp └── README.md ├── 326.Power of Three ├── 326.cpp └── README.md ├── 328.Odd Even Linked List ├── 328.cpp └── README.md ├── 329.Longest Increasing Path in a Matrix ├── 329.cpp └── README.md ├── 33.Search in Rotated Sorted Array ├── 33.cpp └── README.md ├── 334.Increasing Triplet Subsequence ├── 334.cpp └── README.md ├── 34.Search for a Range ├── 34.cpp └── README.md ├── 341.Flatten Nested List Iterator ├── 341.cpp └── README.md ├── 344.Reverse String └── 344.cpp ├── 347.Top K Frequent Elements ├── 347.cpp └── README.md ├── 350.Intersection of Two Arrays II ├── 350.cpp └── README.md ├── 36.Valid Sudoku ├── 36.cpp └── README.md ├── 371.Sum of Two Integers ├── 371.cpp └── README.md ├── 378.Kth Smallest Element in a Sorted Matrix ├── 378.cpp └── README.md ├── 38.Count and Say ├── 38.cpp └── README.md ├── 380.Insert Delete GetRandom O(1) └── 380.cpp ├── 384.Shuffle an Array ├── 384.cpp └── README.md ├── 387.First Unique Character in a String ├── 387.cpp └── README.md ├── 39.Combination Sum ├── 39.cpp └── README.md ├── 395.Longest Substring with At Least K Repeating Characters ├── 395.cpp └── README.md ├── 4.Median of Two Sorted Arrays ├── 4.cpp └── README.md ├── 40.Combination Sum II ├── 40.cpp └── README.md ├── 41.First Missing Positive ├── 41.cpp └── README.md ├── 412.Fizz Buzz ├── 412.cpp └── README.md ├── 42.Trapping Rain Water ├── 42.cpp └── README.md ├── 44.Wildcard Matching ├── 44.cpp └── README.md ├── 45.Jump Game II ├── 45.cpp └── README.md ├── 454.4Sum II ├── 454.cpp └── README.md ├── 46.Permutations ├── 46.cpp └── README.md ├── 47.Permutations II ├── 47.cpp └── README.md ├── 48.Rotate Image ├── 48.cpp └── README.md ├── 49.Group Anagrams ├── 49.cpp └── README.md ├── 5.Longest Palindromic Substring ├── 5.cpp └── README.md ├── 50.Pow(x,n) ├── 50.cpp └── README.md ├── 53.Maximum Subarray ├── 53.cpp └── README.md ├── 54.Spiral Matrix ├── 54.cpp └── README.md ├── 55.Jump Game ├── 55.cpp └── README.md ├── 56.Merge Intervals ├── 56.cpp └── README.md ├── 62.Unique Paths ├── 62.cpp └── README.md ├── 66.Plus One ├── 66.cpp └── README.md ├── 69.Sqrtx ├── 69.cpp └── README.md ├── 695.Max Area of Island ├── 695.cpp └── README.md ├── 7.Reverse Integer ├── 7.cpp └── README.md ├── 70.Climbing Stairs ├── 70.cpp └── README.md ├── 73.Set Matrix Zeroes ├── 73.cpp └── README.md ├── 75.Sort Colors ├── 75.cpp └── README.md ├── 76.Minimum Window Substring ├── 76.cpp └── README.md ├── 78.Subsets ├── 78.cpp └── README.md ├── 79.Word Search ├── 79.cpp └── README.md ├── 8.String to Integer ├── 8.cpp └── README.md ├── 83.Remove Duplicates from Sorted List ├── 83.cpp └── README.md ├── 84.Largest Rectangle in Histogram ├── 84.cpp └── README.md ├── 88.Merge Sorted Array ├── 88.cpp └── README.md ├── 91.Decode Ways ├── 91.cpp └── README.md ├── 94.Binary Tree Inorder Traversal └── 94.cpp ├── 98.Validate Binary Search Tree ├── 98.cpp └── README.md ├── ContainerWithMostWater.c ├── IntegerToRoman.c ├── PalindromeNumber.c ├── README.md ├── RegularExpressionMatch.c ├── RomanToInteger.c ├── ThreeSumClosest.c ├── ZigZag.c └── img ├── 118.png ├── 127-1.png ├── 127-2.png ├── 127-3.png ├── 128.png ├── 14-1.png ├── 14-2.png ├── 146.png ├── 17.png ├── 21-1.png ├── 21-2.png ├── 218-1.png ├── 218-2.png ├── 218-3.png ├── 218.png ├── 24.png ├── 26.png ├── 341.png ├── 42.png ├── 5.png ├── 73.png ├── 84-1.png └── 84.png /1.Two Sum/1.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector twoSum(vector& nums, int target) { 4 | unordered_map map; 5 | vector res; 6 | for(int i = 0;i < nums.size();i++){ 7 | if(map.find(target - nums[i]) != map.end()){ 8 | res.push_back(map[target - nums[i]]); 9 | res.push_back(i); 10 | return res; 11 | } 12 | map[nums[i]] = i; 13 | } 14 | return res; 15 | } 16 | }; -------------------------------------------------------------------------------- /1.Two Sum/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。 4 | 5 | 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。 6 | 7 | 示例: 8 | 9 | ``` 10 | 给定 nums = [2, 7, 11, 15], target = 9 11 | 12 | 因为 nums[0] + nums[1] = 2 + 7 = 9 13 | 所以返回 [0, 1] 14 | ``` 15 | 16 | ## 解答 17 | 18 | 将元素值和小标记录在哈希表中,对于一个数num,可以快速查询哈希表中是否存在target-num,存在则找到答案 19 | 20 | 边遍历边查询,边向哈希表中添加元素,这样方便处理含相同元素的情况 21 | 22 | ```c++ 23 | class Solution { 24 | public: 25 | vector twoSum(vector& nums, int target) { 26 | unordered_map map; 27 | vector res; 28 | for(int i = 0;i < nums.size();i++){ 29 | if(map.find(target - nums[i]) != map.end()){ 30 | res.push_back(map[target - nums[i]]); 31 | res.push_back(i); 32 | return res; 33 | } 34 | map[nums[i]] = i; 35 | } 36 | return res; 37 | } 38 | }; 39 | ``` -------------------------------------------------------------------------------- /10.Regular Expression Matching/10.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isMatch(string s, string p) { 4 | int len1 = s.length(),len2 = p.length(); 5 | 6 | bool **state = new bool*[len1 + 1]; 7 | for(int i = 0;i <= len1;i++) 8 | state[i] = new bool[len2 + 1]; 9 | 10 | //第一列,p = "" 11 | state[0][0] = true; 12 | for(int i = 1;i <= len1;i++) state[i][0] = false; 13 | 14 | //第一行,s = "" 15 | state[0][1] = false; 16 | for(int j = 2;j <= len2;j++) state[0][j] = (p[j - 1] == '*') ? (state[0][j - 2]) : false; 17 | 18 | for(int i = 1;i <= len1;i++) 19 | for(int j = 1;j <= len2;j++){ 20 | if(p[j - 1] == '*') 21 | state[i][j] = state[i][j - 2] || ((p[j - 2] == '.' || p[j - 2] == s[i - 1]) && state[i - 1][j]); 22 | else if(p[j - 1] == '.') 23 | state[i][j] = state[i - 1][j - 1]; 24 | else 25 | state[i][j] = (p[j - 1] == s[i - 1]) && state[i - 1][j - 1]; 26 | } 27 | 28 | return state[len1][len2]; 29 | } 30 | }; -------------------------------------------------------------------------------- /101.Symmetric Tree/101.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool isSymmetric(TreeNode* root) { 13 | if(!root) return true; 14 | 15 | TreeNode *nd1 = root->left,*nd2 = root->right; 16 | return equalNode(nd1,nd2); 17 | } 18 | 19 | private: 20 | bool equalNode(TreeNode* nd1,TreeNode* nd2){ 21 | if(!nd1) return !nd2; 22 | if(!nd2) return false; 23 | 24 | if(nd1->val == nd2->val) 25 | return equalNode(nd1->left,nd2->right) && equalNode(nd1->right,nd2->left); 26 | return false; 27 | } 28 | }; -------------------------------------------------------------------------------- /102.Binary Tree Level Order Traversal/102.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector> levelOrder(TreeNode* root) { 13 | int currLevel = 0,nextLevel = 0; 14 | deque dq; 15 | vector> res; 16 | 17 | if(root){ 18 | dq.push_back(root); 19 | currLevel++; 20 | } 21 | 22 | vector tp; 23 | while(!dq.empty()){ 24 | if(currLevel){ 25 | TreeNode *nd = dq.front(); 26 | tp.push_back(nd->val); 27 | if(nd->left){ 28 | dq.push_back(nd->left); 29 | nextLevel++; 30 | } 31 | if(nd->right){ 32 | dq.push_back(nd->right); 33 | nextLevel++; 34 | } 35 | dq.pop_front(); 36 | --currLevel; 37 | } 38 | if(currLevel == 0){ 39 | currLevel = nextLevel; 40 | nextLevel = 0; 41 | res.push_back(tp); 42 | tp.clear(); 43 | } 44 | } 45 | 46 | return res; 47 | } 48 | }; -------------------------------------------------------------------------------- /102.Binary Tree Level Order Traversal/README.md: -------------------------------------------------------------------------------- 1 | 使用队列实现按层访问 2 | 3 | 使用变量currLevel表示当前层的节点数,使用变量nextLevel表示下一层的节点数 -------------------------------------------------------------------------------- /103.Binary Tree Zigzag Level Order Traversal/103.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector> zigzagLevelOrder(TreeNode* root) { 13 | vector> res; 14 | deque dq; 15 | stack st; 16 | bool leftToright = true; 17 | 18 | if(root) dq.push_back(root); 19 | 20 | vector tp; 21 | while(!dq.empty()){ 22 | TreeNode *nd = dq.front(); 23 | dq.pop_front(); 24 | tp.push_back(nd->val); 25 | if(leftToright){ 26 | if(nd->left) st.push(nd->left); 27 | if(nd->right) st.push(nd->right); 28 | } 29 | else{ 30 | if(nd->right) st.push(nd->right); 31 | if(nd->left) st.push(nd->left); 32 | } 33 | 34 | if(dq.empty()){ 35 | res.push_back(tp); 36 | tp.clear(); 37 | while(!st.empty()){ 38 | dq.push_back(st.top()); 39 | st.pop(); 40 | } 41 | leftToright = !leftToright; 42 | } 43 | } 44 | 45 | return res; 46 | } 47 | }; -------------------------------------------------------------------------------- /103.Binary Tree Zigzag Level Order Traversal/README.md: -------------------------------------------------------------------------------- 1 | 队列dq每次只保存一层的元素,使用一个栈st保存下一层的元素。使用bool变量leftToright记录当前层是否是“从左往右”的顺序遍历 2 | 3 | 在遍历一层元素时: 4 | 5 | * 如果是“从左往右”,因为下一层是“从右往左”,所以先将左子节点压栈,再将右子节点压栈 6 | * 如果是“从右往左”,因为下一层是“从左往右”,所以先将右子节点压栈,再将左子节点压栈 7 | 8 | 在遍历元素时,将元素保存在数组tp中 9 | 10 | 如果队列dq为空,表示遍历完一层,那么将下一层元素从栈st中弹出,压入队列;改变元素的遍历方向;并将这一层的元素数组tp保存到结果数组res中 -------------------------------------------------------------------------------- /104.Maximum Depth of Binary Tree/104.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int maxDepth(TreeNode* root) { 13 | if(!root) return 0; 14 | 15 | return max(maxDepth(root->left) + 1,maxDepth(root->right) + 1); 16 | } 17 | }; -------------------------------------------------------------------------------- /105.Construct Binary Tree from Preorder and Inorder Traversal/105.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* buildTree(vector& preorder, vector& inorder) { 13 | if(preorder.empty() || inorder.empty() || preorder.size() != inorder.size()) 14 | return nullptr; 15 | return buildTree(preorder,0,preorder.size() - 1,inorder,0,inorder.size() - 1); 16 | } 17 | 18 | TreeNode* buildTree(vector &preorder,int b1,int e1,vector &inorder,int b2,int e2) 19 | { 20 | if(e1 < b1 || e2 < b2 || e1 - b1 != e2 - b2) return nullptr; 21 | 22 | int rootval = preorder[b1]; 23 | int count = 0; 24 | for(int i = b2;i <= e2;i++){ 25 | if(inorder[i] != rootval) count++; 26 | else break; 27 | } 28 | 29 | if(count == e2 - b2 + 1) return nullptr; 30 | 31 | TreeNode *root = new TreeNode(rootval); 32 | root->left = buildTree(preorder,b1 + 1,b1 + count,inorder,b2,b2 + count - 1); 33 | root->right = buildTree(preorder,b1 + count + 1,e1,inorder,b2 + count + 1,e2); 34 | 35 | return root; 36 | } 37 | }; -------------------------------------------------------------------------------- /105.Construct Binary Tree from Preorder and Inorder Traversal/README.md: -------------------------------------------------------------------------------- 1 | 前序遍历序列的第一个节点是根节点,可以根据根节点将中序遍历序列划分成左子树区间和右子树区间。根据左子树和右子树节点的个数,又可以将前序遍历序列划分成左子树区间和右子树区间。因此得到了左子树的前序遍历序列和中序遍历序列、右子树的前序遍历序列和中序遍历序列。递归构造左右子树 -------------------------------------------------------------------------------- /108.Convert Sorted Array to Binary Search Tree/108.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* sortedArrayToBST(vector& nums) { 13 | int l = 0,r = nums.size() - 1; 14 | return sortedArrayToBSTCore(nums,l,r); 15 | } 16 | public: 17 | TreeNode* sortedArrayToBSTCore(vector &nums,int l,int r){ 18 | if(l > r) return NULL; 19 | 20 | int mid = (l + r) >> 1; 21 | TreeNode *root = new TreeNode(nums[mid]); 22 | if(l < r){ 23 | root->left = sortedArrayToBSTCore(nums,l,mid - 1); 24 | root->right = sortedArrayToBSTCore(nums,mid + 1,r); 25 | } 26 | 27 | return root; 28 | } 29 | }; -------------------------------------------------------------------------------- /108.Convert Sorted Array to Binary Search Tree/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。 4 | 5 | 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 6 | 7 | 示例: 8 | 9 | ``` 10 | 给定有序数组: [-10,-3,0,5,9], 11 | 12 | 一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树: 13 | 14 | 0 15 | / \ 16 | -3 9 17 | / / 18 | -10 5 19 | ``` 20 | 21 | ## 解答 22 | 23 | 要平衡,那么左右子树节点首先必须相等,因此最开始选择数组中间的元素作为根节点,数组左边的元素用来构造左子树,右边的元素用来构造右子树。由于数组有序,因此满足BST的性质。选择左边数组的中间元素作为左子节点,右边数组的中间元素作为右子节点,从而又保证了以左右子节点为根节点的树的左子树和右子树的元素相等。这样递归构造,最终可以保证平衡: 24 | 25 | ```c++ 26 | /** 27 | * Definition for a binary tree node. 28 | * struct TreeNode { 29 | * int val; 30 | * TreeNode *left; 31 | * TreeNode *right; 32 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 33 | * }; 34 | */ 35 | class Solution { 36 | public: 37 | TreeNode* sortedArrayToBST(vector& nums) { 38 | int l = 0,r = nums.size() - 1; 39 | return sortedArrayToBSTCore(nums,l,r); 40 | } 41 | public: 42 | TreeNode* sortedArrayToBSTCore(vector &nums,int l,int r){ 43 | if(l > r) return NULL; 44 | 45 | int mid = (l + r) >> 1; 46 | TreeNode *root = new TreeNode(nums[mid]); 47 | if(l < r){ 48 | root->left = sortedArrayToBSTCore(nums,l,mid - 1); 49 | root->right = sortedArrayToBSTCore(nums,mid + 1,r); 50 | } 51 | 52 | return root; 53 | } 54 | }; 55 | ``` -------------------------------------------------------------------------------- /109.Convert Sorted List to Binary Search Tree/109.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | /** 10 | * Definition for a binary tree node. 11 | * struct TreeNode { 12 | * int val; 13 | * TreeNode *left; 14 | * TreeNode *right; 15 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 16 | * }; 17 | */ 18 | class Solution { 19 | public: 20 | TreeNode* sortedListToBST(ListNode* head) { 21 | ListNode* p = head; 22 | int count = 0; 23 | while(p) { 24 | count++; 25 | p = p->next; 26 | } 27 | 28 | return sortedListToBSTCore(count,&head); 29 | } 30 | private: 31 | TreeNode* sortedListToBSTCore(int count,ListNode** curr){ 32 | if(count <= 0) return NULL; 33 | 34 | TreeNode *root = new TreeNode(0); 35 | root->left = sortedListToBSTCore(count / 2,curr); 36 | root->val = (*curr)->val; 37 | (*curr) = (*curr)->next; 38 | root->right = sortedListToBSTCore(count - count / 2 - 1,curr); 39 | 40 | return root; 41 | } 42 | }; -------------------------------------------------------------------------------- /11.Container With Most Water/11.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxArea(vector& height) { 4 | int l = 0,r = height.size() - 1; 5 | int res = 0; 6 | while(l < r){ 7 | int minHeight = min(height[l],height[r]); 8 | res = max(res , (r - l) * minHeight); 9 | while(l < r && height[l] <= minHeight) l++; 10 | while(l < r && height[r] <= minHeight) r--; 11 | } 12 | return res; 13 | } 14 | }; -------------------------------------------------------------------------------- /11.Container With Most Water/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。画 n 条垂直线,使得垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 4 | 5 | 注意:你不能倾斜容器,n 至少是2。 6 | 7 | ## 解答 8 | 9 | 使用两个指针l和r,分别指向最左边的垂直线和最右边的垂直线,因此`r-1`就是容器的宽,`min(height[l],height[r])`就是容器的高,可以求出盛水量,为了盛更多的水,需要更大的面积,l和r向中间移动时,宽会变小,那么要得到更大的面积,高必须增加,因此选择l和r中高度较小者向中间移动,直到碰到一个更高的垂直线,此时判断是否更新最大盛水量。这个过程一直持续到`l>=r` 10 | 11 | ```c++ 12 | class Solution { 13 | public: 14 | int maxArea(vector& height) { 15 | int l = 0,r = height.size() - 1; 16 | int res = 0; 17 | while(l < r){ 18 | int minHeight = min(height[l],height[r]); 19 | res = max(res , (r - l) * minHeight); 20 | while(l < r && height[l] <= minHeight) l++; 21 | while(l < r && height[r] <= minHeight) r--; 22 | } 23 | return res; 24 | } 25 | }; 26 | ``` -------------------------------------------------------------------------------- /116.Populating Next Right Pointers in Each Node/116.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for binary tree with next pointer. 3 | * struct TreeLinkNode { 4 | * int val; 5 | * TreeLinkNode *left, *right, *next; 6 | * TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | void connect(TreeLinkNode *root) { 12 | if(!root) 13 | return; 14 | 15 | if(root->left && root->right) 16 | root->left->next = root->right; 17 | 18 | if(root->right && root->next && root->next->left) 19 | root->right->next = root->next->left; 20 | 21 | if(root->left) 22 | connect(root->left); 23 | if(root->right) 24 | connect(root->right); 25 | 26 | } 27 | }; -------------------------------------------------------------------------------- /118.Pascal's Triangle/118.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> generate(int numRows) { 4 | if(numRows <= 0) return vector>(); 5 | 6 | vector> res(1,vector(1,1)); 7 | for(int i = 1;i < numRows;i++){ 8 | vector newline; 9 | newline.push_back(1); 10 | for(int j = 1;j < i;j++){ 11 | newline.push_back(res[i - 1][j - 1] + res[i - 1][j]); 12 | } 13 | newline.push_back(1); 14 | res.push_back(newline); 15 | } 16 | 17 | return res; 18 | } 19 | }; -------------------------------------------------------------------------------- /118.Pascal's Triangle/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行 4 | 5 |
6 | 7 | 示例: 8 | 9 | ``` 10 | 输入: 5 11 | 输出: 12 | [ 13 | [1], 14 | [1,1], 15 | [1,2,1], 16 | [1,3,3,1], 17 | [1,4,6,4,1] 18 | ] 19 | ``` 20 | 21 | ## 解答 22 | 23 | ```num[i][j] = num[i - 1][j - 1] + num[i - 1][j]``` 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | vector> generate(int numRows) { 29 | if(numRows <= 0) return vector>(); 30 | 31 | vector> res(1,vector(1,1)); 32 | for(int i = 1;i < numRows;i++){ 33 | vector newline; 34 | newline.push_back(1); 35 | for(int j = 1;j < i;j++){ 36 | newline.push_back(res[i - 1][j - 1] + res[i - 1][j]); 37 | } 38 | newline.push_back(1); 39 | res.push_back(newline); 40 | } 41 | 42 | return res; 43 | } 44 | }; 45 | ``` -------------------------------------------------------------------------------- /121.Best Time to Buy and Sell Stock/121.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { 4 | int buy = INT_MAX,sell,maxprofit = 0; 5 | for(int i = 0;i < prices.size();i++){ 6 | if(prices[i] < buy) buy = prices[i]; 7 | else if(prices[i] > buy){ 8 | sell = prices[i]; 9 | if(sell - buy > maxprofit) maxprofit = sell - buy; 10 | } 11 | } 12 | return maxprofit; 13 | } 14 | }; -------------------------------------------------------------------------------- /121.Best Time to Buy and Sell Stock/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 4 | 5 | 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 6 | 7 | 注意你不能在买入股票前卖出股票。 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 输入: [7,1,5,3,6,4] 13 | 输出: 5 14 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 15 | 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 16 | ``` 17 | 18 | 示例 2: 19 | 20 | ``` 21 | 输入: [7,6,4,3,1] 22 | 输出: 0 23 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 24 | ``` 25 | 26 | ## 解答 27 | 28 | 遍历数组,如果遇到一个更小的价格,那么更新买入的价钱,否则,如果价格大于买入价格,则执行一次计算,判断是否是更大利润: 29 | 30 | ```c++ 31 | class Solution { 32 | public: 33 | int maxProfit(vector& prices) { 34 | int buy = INT_MAX,sell,maxprofit = 0; 35 | for(int i = 0;i < prices.size();i++){ 36 | if(prices[i] < buy) buy = prices[i]; 37 | else if(prices[i] > buy){ 38 | sell = prices[i]; 39 | if(sell - buy > maxprofit) maxprofit = sell - buy; 40 | } 41 | } 42 | return maxprofit; 43 | } 44 | }; 45 | ``` -------------------------------------------------------------------------------- /122.Best Time to Buy and Sell Stock II/122.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProfit(vector& prices) { 4 | int buy = INT_MAX,maxprofit = 0; 5 | for(int i = 0;i < prices.size();i++){ 6 | if(prices[i] < buy) buy = prices[i]; 7 | else if(prices[i] > buy){ 8 | maxprofit += prices[i] - buy; 9 | buy = prices[i]; 10 | } 11 | } 12 | return maxprofit; 13 | } 14 | }; -------------------------------------------------------------------------------- /122.Best Time to Buy and Sell Stock II/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 4 | 5 | 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 6 | 7 | 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 输入: [7,1,5,3,6,4] 13 | 输出: 7 14 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 15 | 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 16 | ``` 17 | 18 | 示例 2: 19 | 20 | ``` 21 | 输入: [1,2,3,4,5] 22 | 输出: 4 23 | 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 24 | 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 25 | 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 26 | ``` 27 | 28 | 示例 3: 29 | 30 | ``` 31 | 输入: [7,6,4,3,1] 32 | 输出: 0 33 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 34 | ``` 35 | 36 | ## 解答 37 | 38 | 每次如果遇到一个更小的价格,那么更新买入的价格buy。否则,如果遇到一个更大的价格,那么立即结算,将利润加入到结果中,并且更新买入的价格。如果不立即卖出,当遇到一个更大的价格时再卖出,结果也是相同的,但是这样无法预测往后是否会出现更高的价格,所以立即卖出更方便实现。如果不卖出,当遇到一个更小价格时,会更新买入的价格buy,那么这一笔利润就浪费了 39 | 40 | ```c++ 41 | class Solution { 42 | public: 43 | int maxProfit(vector& prices) { 44 | int buy = INT_MAX,maxprofit = 0; 45 | for(int i = 0;i < prices.size();i++){ 46 | if(prices[i] < buy) buy = prices[i]; 47 | else if(prices[i] > buy){ 48 | maxprofit += prices[i] - buy; 49 | buy = prices[i]; 50 | } 51 | } 52 | return maxprofit; 53 | } 54 | }; 55 | ``` -------------------------------------------------------------------------------- /124.Binary Tree Maximum Path Sum/124.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int maxPathSum(TreeNode* root) { 13 | int res = INT_MIN; 14 | maxPathSum(root,res); 15 | 16 | return res; 17 | } 18 | private: 19 | int maxPathSum(TreeNode* root,int &res) { 20 | if(!root) return 0; 21 | 22 | int max; 23 | int leftMax = maxPathSum(root->left,res); 24 | int rightMax = maxPathSum(root->right,res); 25 | if(leftMax <= 0 && rightMax <= 0) //两边都小于等于0 26 | max = root->val; 27 | else if(leftMax <= 0 || rightMax <= 0) //有一边大于0,另一边小于等于0 28 | max = leftMax > rightMax ? leftMax + root->val : rightMax + root->val; 29 | else //两边都大于0 30 | max = leftMax + rightMax + root->val; 31 | 32 | if(max > res) res = max; 33 | 34 | if(leftMax <= 0 && rightMax <= 0) //两边都小于等于0 35 | return root->val; 36 | else //至少有一边大于0 37 | return leftMax > rightMax ? leftMax + root->val : rightMax + root->val; 38 | } 39 | }; -------------------------------------------------------------------------------- /125.Valid Palindrome/125.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isPalindrome(string s) { 4 | for(int l = 0,r = s.length() - 1;l < r;l++,r--) { 5 | while(!isalnum(s[l]) && l < r) {l++;} 6 | while(!isalnum(s[r]) && r > l) {r--;} 7 | if(toupper(s[l]) != toupper(s[r])) return false; 8 | } 9 | return true; 10 | } 11 | }; -------------------------------------------------------------------------------- /125.Valid Palindrome/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 4 | 5 | 说明:本题中,我们将空字符串定义为有效的回文串。 6 | 7 | 示例 1: 8 | 9 | ``` 10 | 输入: "A man, a plan, a canal: Panama" 11 | 输出: true 12 | ``` 13 | 14 | 示例 2: 15 | 16 | ``` 17 | 输入: "race a car" 18 | 输出: false 19 | ``` 20 | 21 | ## 解答 22 | 23 | 注意题目要求,**只考虑字母和数字,同时可以忽略大小写**,意味着其它无效字符会被忽略 24 | 25 | 使用两个变量l和r,一个从字符串左边出发,一个从右边出发,每次都找到一个数字或字母。因为忽略大小写,因此可以统一使用toupper转换为大写进行比较,相等则继续,直到l>=r,说明是一个有效回文。否则不是有效回文 26 | 27 | ```c++ 28 | class Solution { 29 | public: 30 | bool isPalindrome(string s) { 31 | for(int l = 0,r = s.length() - 1;l < r;l++,r--) { 32 | while(!isalnum(s[l]) && l < r) {l++;} 33 | while(!isalnum(s[r]) && r > l) {r--;} 34 | if(toupper(s[l]) != toupper(s[r])) return false; 35 | } 36 | return true; 37 | } 38 | }; 39 | ``` -------------------------------------------------------------------------------- /128.Longest Consecutive Sequence/128.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int longestConsecutive(vector& nums) { 4 | unordered_map map; 5 | 6 | int sz = nums.size(),res = 0; 7 | for(int i = 0;i < sz;i++){ 8 | int idx = nums[i]; 9 | if(map.find(idx) == map.end()){ //只处理没有处理过的数 10 | auto itr_l = map.find(idx - 1); 11 | auto itr_r = map.find(idx + 1); 12 | if(itr_l == map.end() && itr_r == map.end())//不与任何一个区间相连 13 | map[idx] = 1; 14 | else if(itr_l != map.end() && itr_r != map.end()){//连接2个区间 15 | int left = itr_l->second,right = itr_r->second; 16 | map[idx - left] = left + right + 1; 17 | map[idx + right] = left + right + 1; 18 | map[idx] = left + right + 1; 19 | } 20 | else if(itr_l != map.end()){ 21 | int left = itr_l->second; 22 | map[idx - left] = left + 1; 23 | map[idx] = left + 1; 24 | } 25 | else{ 26 | int right = itr_r->second; 27 | map[idx + right] = right + 1; 28 | map[idx] = right + 1; 29 | } 30 | 31 | if(map[idx] > res) res = map[idx]; 32 | } 33 | } 34 | 35 | return res; 36 | } 37 | }; -------------------------------------------------------------------------------- /128.Longest Consecutive Sequence/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个未排序的整数数组,找出最长连续序列的长度 4 | 5 | 要求算法的时间复杂度为 O(n) 6 | 7 | 示例: 8 | 9 | ``` 10 | 输入: [100, 4, 200, 1, 3, 2] 11 | 输出: 4 12 | 解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。 13 | ``` 14 | 15 | ## 解答 16 | 17 | ### 方法一:排序 18 | 19 | 先排序,排序完成后遍历一遍数组就能找出最长连续序列 20 | 21 | ```c++ 22 | class Solution { 23 | public: 24 | int longestConsecutive(vector& nums) { 25 | sort(nums.begin(),nums.end()); 26 | int res = 0,sz = nums.size(); 27 | for(int i = 0;i < sz;i++){ 28 | int j = i,len = 1; 29 | while(j + 1 < sz){ 30 | if(nums[j + 1] == nums[j] + 1) len++; 31 | else if(nums[j + 1] != nums[j]) break; 32 | j++; 33 | } 34 | if(len > res) res = len; 35 | i = j; //j + 1已经不连续,所以i再++就到了第一个不连续的位置 36 | } 37 | return res; 38 | } 39 | }; 40 | ``` 41 | 42 | * **时间复杂度**:O(nlogn)(accept,但不符合要求) 43 | * **空间复杂度**:O(1) 44 | 45 | ### 方法二:hash表 46 | 47 | [参考](https://www.youtube.com/watch?v=rc2QdQ7U78I) 48 | 49 | 使用一个hash表,key表示数,value表示以key为边界的连续序列的长度,很显然,当插入一个数字num时: 50 | 51 | * 如果num已经存在hash表中,那么以前已经处理过,那么忽略 52 | * 否则,又分为几种情况: 53 | - 如果num-1在hash表中,表明num刚好和num-1结尾的序列相连,因此组成一个新的最大连续序列,此时更新区间左边界和右边界(即num)hash表项的value,即最大连续序列的长度 54 | - 如果num+1在hash表中,表明num刚好和num+1开头的序列相连,因此组成一个新的最大连续序列,此时更新区间左边界(即num)和右边界hash表项的value,即最大连续序列的长度 55 | - 如果num-1和num+1都在hash表中,说明num将两个连续序列相连,因此更新左边区间左边界hash项的value,以及右区间右边界hash项的value 56 | 57 | 每次得到一个新的连续序列时,与结果判定,如果更大,那么更新结果。下图为[1,2,3,6,5,4]的示例: 58 | 59 |
60 | 61 | * **时间复杂度**:O(n) 62 | * **空间复杂度**:O(n) -------------------------------------------------------------------------------- /13.Roman to Integer/13.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int romanToInt(string s) { 4 | unordered_map map; 5 | map['I'] = 1; 6 | map['V'] = 5; 7 | map['X'] = 10; 8 | map['L'] = 50; 9 | map['C'] = 100; 10 | map['D'] = 500; 11 | map['M'] = 1000; 12 | int res = map[s[0]],prev = map[s[0]]; 13 | for(int i = 1;i < s.length();i++){ 14 | if(map[s[i]] > prev) 15 | res += map[s[i]] - prev * 2; 16 | else 17 | res += map[s[i]]; 18 | prev = map[s[i]]; 19 | } 20 | return res; 21 | } 22 | }; -------------------------------------------------------------------------------- /130.Surrounded Regions/130.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void solve(vector>& board) { 4 | if(board.empty() || board[0].empty()) return; 5 | 6 | int rows = board.size(); 7 | int cols = board[0].size(); 8 | 9 | for(int i = 0;i < rows;i++){ 10 | if(board[i][0] == 'O') dfs(board,i,0); 11 | if(board[i][cols - 1] == 'O') dfs(board,i,cols - 1); 12 | } 13 | 14 | for(int j = 0;j < cols;j++){ 15 | if(board[0][j] == 'O') dfs(board,0,j); 16 | if(board[rows - 1][j] == 'O') dfs(board,rows - 1,j); 17 | } 18 | 19 | for(int i = 0;i < rows;i++){ 20 | for(int j = 0;j < cols;j++){ 21 | if(board[i][j] == 'O') board[i][j] = 'X'; 22 | else if(board[i][j] == '#') board[i][j] = 'O'; 23 | } 24 | } 25 | } 26 | 27 | void dfs(vector> &board,int row,int col){ 28 | if(row < 0 || col < 0 || row >= board.size() || col >= board[row].size() || board[row][col] != 'O') return; 29 | 30 | board[row][col] = '#'; 31 | 32 | dfs(board,row - 1,col) , dfs(board,row + 1,col) , dfs(board,row,col - 1) , dfs(board,row,col + 1); 33 | } 34 | }; -------------------------------------------------------------------------------- /130.Surrounded Regions/README.md: -------------------------------------------------------------------------------- 1 | **关键在于理解,哪些‘O’应该被改成'X'。由于‘O’不能出现在边界,所以与边界相连的所有'O'都不能改成'X',其余的'O'应该改成'X'** 2 | 3 | 那么可以先遍历4个条边界,如果边界上的某个位置为‘O’,则使用dfs,将包含该'O'的块的元素都设置成‘#’ 4 | 5 | 然后遍历一遍所有元素,此时图中存在3种元素:‘X’、'O'、'#',将所有的'O'改成'X',将所有的'#'改回‘O‘ -------------------------------------------------------------------------------- /131.Palindrome Partitioning/131.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> partition(string s) { 4 | vector> res; 5 | vector path; 6 | 7 | dfs(s,path,res); 8 | 9 | return res; 10 | } 11 | 12 | void dfs(string s,vector &path,vector> &res){ 13 | if(s.empty()) res.push_back(path); 14 | 15 | for(int len = 1;len <= s.size();len++){ 16 | string substr = s.substr(0,len); 17 | if(isPalindrome(substr)){ 18 | path.push_back(substr); 19 | dfs(s.substr(len),path,res); 20 | path.pop_back(); 21 | } 22 | } 23 | } 24 | 25 | private: 26 | bool isPalindrome(const string &str){ 27 | int l = 0,r = str.size() - 1; 28 | while(l < r){ 29 | if(str[l++] == str[r--]) continue; 30 | else return false; 31 | } 32 | return true; 33 | } 34 | }; -------------------------------------------------------------------------------- /131.Palindrome Partitioning/README.md: -------------------------------------------------------------------------------- 1 | 对于字符串str,遍历从下标0开始的每一个子串: 2 | 3 | * 如果子串[0,i]是回文,则将子串添加到路径,递归处理剩余子串[i+1,n] 4 | * 如果子串[0,i]不是回文,处理下一个子串[0,i+1] 5 | * 如果字符串str为空,表示已经递归处理(dfs)到结尾,那么将这条路径添加到结果中 6 | * 每处理完一条路径,递归返回时,需要将之前添加到路径结尾的回文串[0,i]弹出 -------------------------------------------------------------------------------- /134.Gas Station/134.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int canCompleteCircuit(vector& gas, vector& cost) { 4 | int start = 0; //起始位置 5 | int remain = 0; //当前剩余燃料 6 | int debt = 0; //前面没能走完的路上欠的债 7 | 8 | for(int i = 0;i < gas.size();i++){ 9 | remain += gas[i] - cost[i]; 10 | if(remain < 0){ 11 | start = i + 1; 12 | debt += remain; 13 | remain = 0; 14 | } 15 | } 16 | 17 | return debt + remain >= 0 ? start : -1; 18 | } 19 | }; -------------------------------------------------------------------------------- /136.Single Number/136.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int singleNumber(vector& nums) { 4 | int res = 0; 5 | for(int i = 0;i < nums.size();i++){ 6 | res ^= nums[i]; 7 | } 8 | return res; 9 | } 10 | }; -------------------------------------------------------------------------------- /136.Single Number/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 4 | 5 | 说明: 6 | 7 | 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 输入: [2,2,1] 13 | 输出: 1 14 | ``` 15 | 16 | 示例 2: 17 | 18 | ``` 19 | 输入: [4,1,2,1,2] 20 | 输出: 4 21 | ``` 22 | 23 | ## 解答 24 | 25 | 一个数和自身异或为0。0和任何数异或都得那个数。因此将所有数异或,出现2次的都为0,最终剩下只出现1次的数 26 | 27 | ```c++ 28 | class Solution { 29 | public: 30 | int singleNumber(vector& nums) { 31 | int res = 0; 32 | for(int i = 0;i < nums.size();i++){ 33 | res ^= nums[i]; 34 | } 35 | return res; 36 | } 37 | }; 38 | ``` -------------------------------------------------------------------------------- /137.Single Number II/137.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int singleNumber(vector& nums) { 4 | int bits = sizeof(int) * 8; 5 | int pos = 1,res = 0; 6 | 7 | while(bits--){ 8 | int sum = 0; 9 | for(int num : nums){ 10 | sum += ((num & pos) == 0 ? 0 : 1); 11 | } 12 | if(sum % 3 == 1) res |= pos; 13 | pos = pos << 1; 14 | } 15 | 16 | return res; 17 | } 18 | }; -------------------------------------------------------------------------------- /137.Single Number II/README.md: -------------------------------------------------------------------------------- 1 | 如果其余数字都出现2次,则使用异或很好解决,但是这里是3次,所以无法使用异或;但是还是可以沿用位运算的思路,如果一个数字出现3次,其二进制表示的每一位也出现3次,把所有出现3次的数字的二进制表示的每一位都分别加起来,每一位的和都能被3整除。我们把数组中所有数字的二进制表示的每一位都加起来。如果某一位的和能被3整除,那么只出现一次的数字二进制中对应的那一位是0,否则是1; -------------------------------------------------------------------------------- /138.Copy List with Random Pointer/138.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list with a random pointer. 3 | * struct RandomListNode { 4 | * int label; 5 | * RandomListNode *next, *random; 6 | * RandomListNode(int x) : label(x), next(NULL), random(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | RandomListNode *copyRandomList(RandomListNode *head) { 12 | if(!head) return NULL; 13 | 14 | RandomListNode *p = head; 15 | while(p){ 16 | RandomListNode *nd = new RandomListNode(p->label); 17 | nd->next = p->next; 18 | p->next = nd; 19 | p = nd->next; 20 | } 21 | 22 | //这一轮循环不能拆链表,因为后面的节点的random可能指向前面的节点, 23 | //如果在设置random成员的同时拆链表,由于前面的节点已经拆开,所以新链表 24 | //节点的random成员会指向旧链表的节点 25 | p = head; 26 | while(p){ 27 | if(p->random) 28 | p->next->random = p->random->next; 29 | p = p->next->next; 30 | } 31 | 32 | p = head; 33 | head = p->next; //更新head指向复制出的新链表的表头 34 | while(p){ 35 | RandomListNode *tp = p->next; 36 | p->next = tp->next; 37 | p = p->next; 38 | if(p) 39 | tp->next = p->next; 40 | } 41 | 42 | return head; 43 | } 44 | }; -------------------------------------------------------------------------------- /138.Copy List with Random Pointer/README.md: -------------------------------------------------------------------------------- 1 | 第一轮复制节点,使新节点链接在旧链表对应节点的后面: 2 | 3 | ``` 4 | ------- ------- ------- ------- 5 | ... -> | 旧nd i | ->| 新nd i | ->|旧nd i+1| -> |新nd i+1| -> ... 6 | ------- ------- ------- ------- 7 | ``` 8 | 9 | 第二轮遍历复制random,新节点的random指向对应旧节点random指向节点对应的新节点,因为现在对应的新节点在旧节点之后,所以新节点的random指向对应纠结点random指向节点的下一节点 10 | 11 | 第三轮遍历将新链表的节点和旧链表的节点拆开,成为2个链表(这一步不能与第二轮遍历合并,因为后面的节点的random可能指向前面的节点,如果在设置random成员的同时拆链表,由于前面的节点已经拆开,所以新链表节点的random成员会指向旧链表的节点) -------------------------------------------------------------------------------- /139.Word Break/139.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool wordBreak(string s, vector& wordDict) { 4 | unordered_set dict(wordDict.begin(),wordDict.end()); 5 | bool *state = new bool[s.size() + 1]; 6 | for(int i = 0;i < s.size();i++) state[i] = false; 7 | state[s.size()] = true; 8 | 9 | for(int idx = s.size() - 1;idx >= 0;idx--){ 10 | for(int len = 1;len <= s.size() - idx && !state[idx];len++) 11 | if(dict.find(s.substr(idx,len)) != dict.end()) 12 | state[idx] = state[idx + len]; 13 | } 14 | 15 | return state[0]; 16 | } 17 | }; -------------------------------------------------------------------------------- /139.Word Break/README.md: -------------------------------------------------------------------------------- 1 | **动态规划** 2 | 3 | 对于字符串“leetcode”: 4 | 5 | * 如果字符串"l"存在于字典中,则字符串"leetcode"能否由字典中的单词构成取决于字符串“eetcode”能否由字典中的单词构成 6 | * 如果字符串“l”不在字典中,则判断字符串“le”是否字典中,如果在,则字符串“leetcode”能否由字典中的单词构成取决于字符串“etcode”能否由字典中的单词构成 7 | * 如果字符串“le”也不在字典中,那么判断字符串"lee"是否在字典中,如果在,则字符串“leetcode”能否由字典中的单词构成取决于字符串"tcode"能否由字典中的单词构成 8 | * ... 9 | 10 | 令state[i]表示字符串中从下标i开始到结尾的子串能否由字典中的单词构成。对于"leetcode": 11 | 12 | * state[0]就表示“leetcode”能否由字典中的单词构成 13 | * state[2]就表示“leetcode”能否由字典中的单词构成 14 | * state[8]就表示""能够由字典中的单词构成 15 | 16 | 假设substr(i,j)表示字符串s中下标i到下标j的子串,那么state[i] = dict.contain(substr(i,j)) && state[j + 1] 17 | 18 | * **时间复杂度**:O(n^2)(n为字符串长度) 19 | * **空间复杂度**:O(n + m)(n为字符串长度,m为字典中单词数) 20 | -------------------------------------------------------------------------------- /14.Longest Common Prefix/14.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string longestCommonPrefix(vector& strs) { 4 | if(strs.size() == 0) return ""; 5 | if(strs.size() == 1) return strs[0]; 6 | 7 | string res = ""; 8 | int i = 0; 9 | while(i < strs[0].length()){ 10 | char c = strs[0][i]; 11 | int j = 1; 12 | for(;j < strs.size() && i < strs[j].length();j++) 13 | if(strs[j][i] != c) 14 | break; 15 | if(j < strs.size()) return res; 16 | else{ 17 | res += c; 18 | i++; 19 | } 20 | } 21 | return res; 22 | } 23 | }; -------------------------------------------------------------------------------- /141.Linked List Cycle/141.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | bool hasCycle(ListNode *head) { 12 | ListNode *slow = head,*fast = head; 13 | while(fast){ 14 | if(fast->next){ 15 | fast = fast->next->next; 16 | slow = slow->next; 17 | if(fast == slow) return true; 18 | } 19 | else 20 | return false; 21 | } 22 | return false; 23 | } 24 | }; -------------------------------------------------------------------------------- /141.Linked List Cycle/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个链表,判断链表中是否有环。 4 | 5 | 进阶: 6 | 7 | 你能否不使用额外空间解决此题? 8 | 9 | ## 解答 10 | 11 | 使用1个快指针和1个慢指针,如果存在环,2个指针必然在环内相遇 12 | 13 | ```c++ 14 | /** 15 | * Definition for singly-linked list. 16 | * struct ListNode { 17 | * int val; 18 | * ListNode *next; 19 | * ListNode(int x) : val(x), next(NULL) {} 20 | * }; 21 | */ 22 | class Solution { 23 | public: 24 | bool hasCycle(ListNode *head) { 25 | ListNode *slow = head,*fast = head; 26 | while(fast){ 27 | if(fast->next){ 28 | fast = fast->next->next; 29 | slow = slow->next; 30 | if(fast == slow) return true; 31 | } 32 | else 33 | return false; 34 | } 35 | return false; 36 | } 37 | }; 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /146.LRU Cache/146.cpp: -------------------------------------------------------------------------------- 1 | class LRUCache { 2 | public: 3 | LRUCache(int capacity) : hashtable() , ls() , cap(capacity) , curr(0) {} 4 | 5 | int get(int key) { 6 | if(hashtable.find(key) == hashtable.end()) return -1; 7 | auto itr = hashtable[key]; 8 | if(itr == ls.begin()) 9 | return itr->second; 10 | else{ 11 | ls.push_front(pair(itr->first,itr->second)); 12 | auto new_itr = ls.begin(); 13 | hashtable[key] = new_itr; 14 | ls.erase(itr); 15 | return ls.front().second; 16 | } 17 | return 1; 18 | } 19 | 20 | void put(int key, int value) { 21 | if(hashtable.find(key) != hashtable.end()){ 22 | ls.erase(hashtable[key]); 23 | ls.push_front(pair(key,value)); 24 | auto new_itr = ls.begin(); 25 | hashtable[key] = new_itr; 26 | return; 27 | } 28 | if(curr == cap){ 29 | hashtable.erase(ls.back().first); 30 | ls.pop_back(); 31 | curr--; 32 | } 33 | ls.push_front(pair(key,value)); 34 | auto new_itr = ls.begin(); 35 | hashtable[key] = new_itr; 36 | curr++; 37 | } 38 | private: 39 | unordered_map>::iterator> hashtable; 40 | list> ls; 41 | int cap; 42 | int curr; 43 | }; 44 | 45 | /** 46 | * Your LRUCache object will be instantiated and called as such: 47 | * LRUCache obj = new LRUCache(capacity); 48 | * int param_1 = obj.get(key); 49 | * obj.put(key,value); 50 | */ -------------------------------------------------------------------------------- /148.Sort List/148.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* sortList(ListNode* head) { 12 | if(!head || !head->next) return head; 13 | 14 | ListNode *middle = getMiddle(head); //找出中间节点需要O(n)的时间 15 | ListNode *head2 = middle->next; 16 | middle->next = NULL; 17 | 18 | //每一轮归并需要O(n)的时间,需要归并log(n)轮 19 | return merge(sortList(head),sortList(head2)); 20 | } 21 | 22 | private: 23 | //case1:空链表,返回空 24 | //case2:n个节点,n为奇数,返回中间的节点 25 | //case3:n个节点,n为偶数,返回左半部最后一个节点 26 | ListNode* getMiddle(ListNode* head){ 27 | if(!head) return head; 28 | 29 | ListNode *slow = head,*quick = head; 30 | while(quick->next && quick->next->next){ 31 | quick = quick->next->next; 32 | slow = slow->next; 33 | } 34 | return slow; 35 | } 36 | 37 | ListNode* merge(ListNode* head1,ListNode* head2){ 38 | ListNode dummy(0); 39 | ListNode *curr = &dummy; 40 | 41 | while(head1 && head2){ 42 | if(head1->val <= head2->val){ 43 | curr->next = head1; 44 | head1 = head1->next; 45 | } 46 | else{ 47 | curr->next = head2; 48 | head2 = head2->next; 49 | } 50 | curr = curr->next; 51 | } 52 | if(!head1) curr->next = head2; 53 | else curr->next = head1; 54 | return dummy.next; 55 | } 56 | }; -------------------------------------------------------------------------------- /149.Max Points on a Line/149.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a point. 3 | * struct Point { 4 | * int x; 5 | * int y; 6 | * Point() : x(0), y(0) {} 7 | * Point(int a, int b) : x(a), y(b) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | int maxPoints(vector& points) { 13 | int num = points.size(); 14 | int res = 0; 15 | for(int i = 0;i < num;i++){ 16 | map,int> lines; 17 | int samePoints = 1,localmax = 0; 18 | for(int j = i + 1;j < num;j++){ 19 | if(points[i].x == points[j].x && points[i].y == points[j].y) 20 | samePoints++; 21 | else 22 | localmax = max(localmax,++lines[getSlope(points[i],points[j])]); 23 | } 24 | res = max(res,localmax + samePoints); 25 | } 26 | return res; 27 | } 28 | private: 29 | pair getSlope(const Point &p1,const Point &p2){ 30 | int dx = p1.x - p2.x; 31 | int dy = p1.y - p2.y; 32 | 33 | if(dx == 0) return pair(0,p1.y); 34 | if(dy == 0) return pair(p1.x,0); 35 | 36 | int d = gcd(dx,dy); 37 | 38 | return pair(dx/d,dy/d); 39 | } 40 | 41 | //求最大公约数 42 | int gcd(int x,int y){ 43 | return y == 0 ? x : gcd(y,x % y); 44 | } 45 | }; -------------------------------------------------------------------------------- /15.3Sum/15.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> threeSum(vector& nums) { 4 | if(nums.size() < 3) return vector>(); 5 | 6 | sort(nums.begin(),nums.end()); 7 | 8 | vector> res; 9 | 10 | for(int i = 0;i < nums.size() - 2;i++){ 11 | if(i == 0 || nums[i] != nums[i - 1]){ 12 | int target = 0 - nums[i]; 13 | int l = i + 1,r = nums.size() - 1; 14 | while(l < r){ 15 | int sum = nums[l] + nums[r]; 16 | if(sum < target){ 17 | while(l < r && nums[l + 1] == nums[l]) l++; 18 | l++; 19 | } 20 | else if(sum > target){ 21 | while(l < r && nums[r - 1] == nums[r]) r--; 22 | r--; 23 | } 24 | else{ 25 | vector triplet = {nums[i],nums[l],nums[r]}; 26 | res.push_back(triplet); 27 | while(l < r && nums[l + 1] == nums[l]) l++; 28 | while(l < r && nums[r - 1] == nums[r]) r--; 29 | l++;r--; 30 | } 31 | } 32 | } 33 | } 34 | 35 | return res; 36 | } 37 | }; -------------------------------------------------------------------------------- /150.Evaluate Reverse Polish Notation/150.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int evalRPN(vector& tokens) { 4 | stack nums; 5 | for(const string &s : tokens){ 6 | if(s == "+"){ 7 | int num = nums.top(); 8 | nums.pop(); 9 | nums.top() = nums.top() + num; 10 | } 11 | else if(s == "-"){ 12 | int num = nums.top(); 13 | nums.pop(); 14 | nums.top() = nums.top() - num; 15 | } 16 | else if(s == "*"){ 17 | int num = nums.top(); 18 | nums.pop(); 19 | nums.top() = nums.top() * num; 20 | } 21 | else if(s == "/"){ 22 | int num = nums.top(); 23 | nums.pop(); 24 | nums.top() = nums.top() / num; 25 | } 26 | else{ 27 | nums.push(stoi(s)); 28 | } 29 | } 30 | return nums.top(); 31 | } 32 | }; -------------------------------------------------------------------------------- /150.Evaluate Reverse Polish Notation/README.md: -------------------------------------------------------------------------------- 1 | 使用一个栈保存数值,如果遇到一个运算符,则弹出栈顶的2个元素,运算后的结果压回栈中 -------------------------------------------------------------------------------- /152.Maximum Product Subarray/152.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxProduct(vector& nums) { 4 | if(nums.empty()) return 0; 5 | 6 | int max_global = nums[0]; 7 | int max_local = nums[0],min_local = nums[0]; 8 | 9 | for(int i = 1;i < nums.size();i++){ 10 | int _max = max(max_local * nums[i],min_local * nums[i],nums[i]); 11 | int _min = min(max_local * nums[i],min_local * nums[i],nums[i]); 12 | max_local = _max; 13 | min_local = _min; 14 | if(max_local > max_global) max_global = max_local; 15 | } 16 | 17 | return max_global; 18 | } 19 | private: 20 | int max(int num1,int num2,int num3){ 21 | return num1 > num2 ? (num1 > num3 ? num1 : num3) : (num2 > num3 ? num2 : num3); 22 | } 23 | 24 | int min(int num1,int num2,int num3){ 25 | return num1 < num2 ? (num1 < num3 ? num1 : num3) : (num2 < num3 ? num2 : num3); 26 | } 27 | }; -------------------------------------------------------------------------------- /155.Min Stack/155.cpp: -------------------------------------------------------------------------------- 1 | class MinStack { 2 | public: 3 | /** initialize your data structure here. */ 4 | MinStack() : valueS() , minS() { 5 | 6 | } 7 | 8 | void push(int x) { 9 | valueS.push(x); 10 | //第一个条件容易漏 11 | if(minS.empty() || x < minS.top()) minS.push(x); 12 | else minS.push(minS.top()); 13 | } 14 | 15 | void pop() { 16 | valueS.pop(); 17 | minS.pop(); 18 | } 19 | 20 | int top() { 21 | return valueS.top(); 22 | } 23 | 24 | int getMin() { 25 | return minS.top(); 26 | } 27 | private: 28 | stack valueS; 29 | stack minS; 30 | }; 31 | 32 | /** 33 | * Your MinStack object will be instantiated and called as such: 34 | * MinStack obj = new MinStack(); 35 | * obj.push(x); 36 | * obj.pop(); 37 | * int param_3 = obj.top(); 38 | * int param_4 = obj.getMin(); 39 | */ -------------------------------------------------------------------------------- /155.Min Stack/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 4 | 5 | * push(x) -- 将元素 x 推入栈中。 6 | * pop() -- 删除栈顶的元素。 7 | * top() -- 获取栈顶元素。 8 | * getMin() -- 检索栈中的最小元素。 9 | 10 | 示例: 11 | 12 | ``` 13 | MinStack minStack = new MinStack(); 14 | minStack.push(-2); 15 | minStack.push(0); 16 | minStack.push(-3); 17 | minStack.getMin(); --> 返回 -3. 18 | minStack.pop(); 19 | minStack.top(); --> 返回 0. 20 | minStack.getMin(); --> 返回 -2. 21 | ``` 22 | 23 | ## 解答 24 | 25 | 使用一个辅助栈保证最小值,该栈的栈顶保存了当前栈中元素的最小值。因此,对于一个新元素,如果小于栈顶元素,那么最小值栈中压入新的元素,否则,继续压入最小值栈的栈顶元素 26 | 27 | ```c++ 28 | class MinStack { 29 | public: 30 | /** initialize your data structure here. */ 31 | MinStack() : valueS() , minS() { 32 | 33 | } 34 | 35 | void push(int x) { 36 | valueS.push(x); 37 | //第一个条件容易漏 38 | if(minS.empty() || x < minS.top()) minS.push(x); 39 | else minS.push(minS.top()); 40 | } 41 | 42 | void pop() { 43 | valueS.pop(); 44 | minS.pop(); 45 | } 46 | 47 | int top() { 48 | return valueS.top(); 49 | } 50 | 51 | int getMin() { 52 | return minS.top(); 53 | } 54 | private: 55 | stack valueS; 56 | stack minS; 57 | }; 58 | 59 | /** 60 | * Your MinStack object will be instantiated and called as such: 61 | * MinStack obj = new MinStack(); 62 | * obj.push(x); 63 | * obj.pop(); 64 | * int param_3 = obj.top(); 65 | * int param_4 = obj.getMin(); 66 | */ 67 | ``` -------------------------------------------------------------------------------- /160.Intersection of Two Linked Lists/160.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 12 | ListNode *pA = headA,*pB = headB; 13 | 14 | if(!pA || !pB) return NULL; 15 | 16 | while(pA || pB){ 17 | if(pA == pB) return pA; 18 | else{ 19 | if(!pA) { 20 | pA = headB; 21 | pB = pB -> next; 22 | } 23 | else if(!pB) { 24 | pB = headA; 25 | pA = pA -> next; 26 | } 27 | else { 28 | pA = pA -> next; 29 | pB = pB -> next; 30 | } 31 | } 32 | } 33 | 34 | return NULL; 35 | } 36 | }; -------------------------------------------------------------------------------- /160.Intersection of Two Linked Lists/README.md: -------------------------------------------------------------------------------- 1 | ## Solution 2 | 3 | ### Approach #2(Hash Table) [Accepted] 4 | 5 | 遍历其中一个链表,如A。将链表中的每一个节点的地址存入hash set,然后遍历链表B,找出B中的每一个节点是否在hash set中,如果存在,则第一个查找到的节点就是相交节点的开始节点 6 | 7 | #### 复杂度分析 8 | 9 | * 时间复杂度:O(m+n) 10 | * 空间复杂度:O(n) or O(m) 11 | 12 | ### Approach #3(Two Pointer) [Accepted] 13 | 14 | * 维护两个指针pA和pB,分别初始化为链表A和B的head结点。然后让两者每次一个节点的遍历链表 15 | * 当pA到达链表结尾时,让其指向链表B的head节点。同样的,当pB到达链表结尾时,让其指向链表A的head节点 16 | * 如果在任意节点内pA与pB相遇,则pA/pB就是所求的相交节点 17 | 18 | >解释:假设A={1,3,5,7,9,11},B={2,4,9,11},因此,所求得的相交节点应该是9。由于B链表更短,所以pB将会先到达结尾。此时pB比pA少遍历2个节点就到达了结尾,将pB指向链表A的head结点,继续遍历。当pA也遍历完链表后,使其指向链表B的head节点。因此,在第二次迭代中,pA可以比pB少遍历2个节点 19 | 20 | #### 复杂度分析 21 | 22 | * 时间复杂度:O(m+n) 23 | * 空间复杂度:O(1) -------------------------------------------------------------------------------- /162.Find Peak Element/162.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findPeakElement(vector& nums) { 4 | int ret = -1; 5 | int l = 0,r = nums.size() - 1,mid; 6 | while(l < r){ 7 | mid = (l + r) >> 1; 8 | if(nums[mid] < nums[mid + 1]) 9 | l = mid + 1; 10 | else if(nums[mid] > nums[mid + 1]) 11 | r = mid; 12 | //假设输入合法,如果nums[mid] == nums[mid+1]会无限循环 13 | //为了代码的简洁性暂时不处理这种情况 14 | } 15 | return l == r ? l : -1; 16 | } 17 | }; -------------------------------------------------------------------------------- /162.Find Peak Element/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 线性查找 3 | 4 | 遍历数组,对于每个元素,如果该元素的前一元素和后一元素都小于该元素,那么该元素是一个峰值,返回 5 | 6 | * 时间复杂度:O(n) 7 | * 空间复杂度:O(1) 8 | 9 | ## 二分查找 10 | 11 | * 如果中间元素比右边的元素小,意味着当前处于一个“降序”中,那么左边(包含当前元素)将会出现一个峰值 12 | * 如果中间元素比右边的元素大,意味着当前处于一个“升序”中,那么右边(不含当前元素)将会出现一个峰值 13 | * 如果中间元素等于右边的元素,那么无法减小区间(所以题目给出了nums[i]不等于nums[i+1]) 14 | 15 | 使用上述判断一直减小区间,直到区间只有1个元素 16 | 17 | * 时间复杂度:O(logn) 18 | * 空间复杂度:O(1) -------------------------------------------------------------------------------- /166.Fraction to Recurring Decimal/166.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string fractionToDecimal(int numerator, int denominator) { 4 | if(denominator == 0) return ""; 5 | if(numerator == 0) return "0"; 6 | 7 | bool negative = (numerator < 0) ^ (denominator < 0); 8 | long long lnumerator = abs((long long)numerator); 9 | long long ldenominator = abs((long long)denominator); 10 | unordered_map map;// 11 | string res = (negative ? "-" : "") + to_string(lnumerator / ldenominator) + (lnumerator % ldenominator ? "." : ""); 12 | lnumerator = lnumerator % ldenominator; 13 | 14 | while(lnumerator && map.find(lnumerator) == map.end()){ 15 | map[lnumerator]=res.size(); 16 | lnumerator *= 10; 17 | res = res + to_string(lnumerator / ldenominator); 18 | lnumerator = lnumerator % ldenominator; 19 | } 20 | 21 | if(lnumerator){ 22 | int idx = map.find(lnumerator)->second; 23 | res = res.substr(0,idx) + "(" + res.substr(idx) + ")"; 24 | } 25 | 26 | return res; 27 | } 28 | }; -------------------------------------------------------------------------------- /166.Fraction to Recurring Decimal/README.md: -------------------------------------------------------------------------------- 1 | 首先将分子和分母都转化为正数(由于最小负整数转化成正整数会越界,所以使用long long),并且记录结果是否是负数 2 | 3 | 计算得出整数部分,根据是否存在余数决定有没有小数点 4 | 5 | 如果有余数,则处理小数部分: 6 | 7 | * 使用map判断是否出现循环,map的key为除数,value为对应的小数部位的下标 8 | - 如果出现循环,则停止处理 9 | - 否则,向map中添加新项,并且向结果字符串尾部添加除得的商 10 | * 根据最终余数是否为0判断在处理小数部分时,是否出现循环,出现则添加括号 11 | 12 | -------------------------------------------------------------------------------- /169.Majority Element/169.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int majorityElement(vector& nums) { 4 | if(nums.empty()) return 0; 5 | 6 | int count = 1,res = nums[0]; 7 | for(int i = 1;i < nums.size();i++){ 8 | if(count == 0){ 9 | res = nums[i]; 10 | count = 1; 11 | } 12 | else{ 13 | if(nums[i] == res) count++; 14 | else count--; 15 | } 16 | } 17 | return res; 18 | } 19 | }; -------------------------------------------------------------------------------- /169.Majority Element/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 4 | 5 | 你可以假设数组是非空的,并且给定的数组总是存在众数。 6 | 7 | 示例 1: 8 | 9 | ``` 10 | 输入: [3,2,3] 11 | 输出: 3 12 | ``` 13 | 14 | 示例 2: 15 | 16 | ``` 17 | 输入: [2,2,1,1,1,2,2] 18 | 输出: 2 19 | ``` 20 | 21 | ## 解答 22 | 23 | 该数字出现的次数超过其它数字出现的次数之和(因此,考虑使用2个变量,一个保存数字,一个保存次数。当遍历到下一个数字时,如果下一数字和之前保存的数字相同,则次数加1,如果下一数字和之前保存的数字不同,则次数减1。如果次数为0,则需保存下一个数字,并把次数设为1,最后一次把次数设为1时对应的数字就是结果)​ 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | int majorityElement(vector& nums) { 29 | if(nums.empty()) return 0; 30 | 31 | int count = 1,res = nums[0]; 32 | for(int i = 1;i < nums.size();i++){ 33 | if(count == 0){ 34 | res = nums[i]; 35 | count = 1; 36 | } 37 | else{ 38 | if(nums[i] == res) count++; 39 | else count--; 40 | } 41 | } 42 | return res; 43 | } 44 | }; 45 | ``` -------------------------------------------------------------------------------- /17.Letter Combinations of a Phone Number/README.md: -------------------------------------------------------------------------------- 1 | 2 | 对于每个当前正在处理的数字,遍历这个数字的所有字母,将其添加到所有结果字符串的末尾,组成新的结果,然后处理下一个数字 3 | 4 | ![](../img/17.png) -------------------------------------------------------------------------------- /171.Excel Sheet Column Number/171.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int titleToNumber(string s) { 4 | int res = 0; 5 | for(char c : s){ 6 | res = res * 26 + (c - 'A' + 1); 7 | } 8 | return res; 9 | } 10 | }; -------------------------------------------------------------------------------- /171.Excel Sheet Column Number/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个Excel表格中的列名称,返回其相应的列序号。 4 | 5 | 例如, 6 | 7 | ``` 8 | A -> 1 9 | B -> 2 10 | C -> 3 11 | ... 12 | Z -> 26 13 | AA -> 27 14 | AB -> 28 15 | ... 16 | ``` 17 | 18 | 示例 1: 19 | 20 | ``` 21 | 输入: "A" 22 | 输出: 1 23 | ``` 24 | 25 | 示例 2: 26 | 27 | ``` 28 | 输入: "AB" 29 | 输出: 28 30 | ``` 31 | 32 | 示例 3: 33 | 34 | ``` 35 | 输入: "ZY" 36 | 输出: 701 37 | ``` 38 | 39 | ## 解答 40 | 41 | ### 方法一:从右往左 42 | 43 | ```c++ 44 | class Solution { 45 | public: 46 | int titleToNumber(string s) { 47 | int res = 0,tp = 1; 48 | for(int i = s.length() - 1;i >= 0;i--){ 49 | res += (s[i] - 'A' + 1) * tp; 50 | tp *= 26; 51 | } 52 | return res; 53 | } 54 | }; 55 | ``` 56 | 57 | ### 方法二:从左往右 58 | 59 | ```c++ 60 | class Solution { 61 | public: 62 | int titleToNumber(string s) { 63 | int res = 0; 64 | for(char c : s){ 65 | res = res * 26 + (c - 'A' + 1); 66 | } 67 | return res; 68 | } 69 | }; 70 | ``` -------------------------------------------------------------------------------- /172.Factorial Trailing Zeroes/172.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int trailingZeroes(int n) { 4 | long long num = 5; 5 | int count = 0; 6 | while(num <= n){ 7 | count += (n / num); 8 | num *= 5; 9 | } 10 | return count; 11 | } 12 | }; -------------------------------------------------------------------------------- /172.Factorial Trailing Zeroes/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个整数 n,返回 n! 结果尾数中零的数量。 4 | 5 | 示例 1: 6 | 7 | ``` 8 | 输入: 3 9 | 输出: 0 10 | 解释: 3! = 6, 尾数中没有零。 11 | ``` 12 | 13 | 示例 2: 14 | 15 | ``` 16 | 输入: 5 17 | 输出: 1 18 | 解释: 5! = 120, 尾数中有 1 个零. 19 | ``` 20 | 21 | 说明: 你算法的时间复杂度应为对数级 22 | 23 | ## 解答 24 | 25 | 10=2\*5,因此,每一对(2,5)就可以产生一个0 26 | 27 | 由于每个偶数中就可以分解出一个因子2,因此n!中,2的个数肯定比5多,所以问题转换为求1~n中,可以分解出多少个因子5: 28 | 29 | ``` 30 | 5,10,15,20,25,30,...,125,130,... 31 | ``` 32 | 33 | 因此,n/5就可以就得有多少个数能分解出1个5 34 | 35 | 但是注意上面的25和125: 36 | 37 | ``` 38 | 25 = 5 * 5; 39 | 125 = 5 * 5 * 5; 40 | ``` 41 | 42 | 这些数中可以分解出多个5,因此,还需要求1~n中,能分解出多少个25,125... 43 | 44 | ``` 45 | 25,50,75,100,125,150,... 46 | //等价于1*(5*5),2*(5*5),3*(5*5),...,5*(5*5),...,这些数中的5还需要加1次 47 | 48 | 125,250,375,... 49 | //等价于1*(5*5*5),2*(5*5*5),3*(5*5*5),...,这些数中的5又要多加1次 50 | 51 | ... 52 | ``` 53 | 54 | 故,设num=5,每次累加n/num后,num就需要乘以5。知道num>n: 55 | 56 | ```c++ 57 | class Solution { 58 | public: 59 | int trailingZeroes(int n) { 60 | long long num = 5; 61 | int count = 0; 62 | while(num <= n){ 63 | count += (n / num); 64 | num *= 5; 65 | } 66 | return count; 67 | } 68 | }; 69 | ``` 70 | 71 | 注意,num的类型为long long,原因在于使用int时可能溢出,例如: 72 | 73 | ``` 74 | 当 n = 1808548329时,如果num为int,在num>n之前,num的值: 75 | 76 | 5 77 | 25 78 | 125 79 | 625 80 | 3125 81 | 15625 82 | 78125 83 | 390625 84 | 1953125 85 | 9765625 86 | 48828125 87 | 244140625 88 | 1220703125 89 | 1808548329 //这里开始溢出 90 | 452807053 91 | -2030932031 92 | -1564725563 93 | 766306777 94 | -463433411 95 | 96 | INT_MAX:2147483647 97 | ``` -------------------------------------------------------------------------------- /179.Largest Number/179.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string largestNumber(vector& nums) { 4 | sort(nums.begin(),nums.end(),[](const int &num1,const int &num2){ 5 | return to_string(num2) + to_string(num1) < to_string(num1) + to_string(num2); 6 | }); 7 | 8 | //处理所有元素都是0的情况 9 | if(!nums.empty() && nums[0] == 0) return "0"; 10 | 11 | string res = ""; 12 | for(int num : nums) res = res + to_string(num); 13 | 14 | return res; 15 | } 16 | }; -------------------------------------------------------------------------------- /179.Largest Number/README.md: -------------------------------------------------------------------------------- 1 | ## 使用函数 2 | 3 | ```c++ 4 | class Solution { 5 | public: 6 | string largestNumber(vector& nums) { 7 | sort(nums.begin(),nums.end(),comp); 8 | 9 | //处理所有元素都是0的情况 10 | if(!nums.empty() && nums[0] == 0) return "0"; 11 | 12 | string res = ""; 13 | for(int num : nums) res = res + to_string(num); 14 | 15 | return res; 16 | } 17 | private: 18 | static bool comp(int num1,int num2){ 19 | string s1 = to_string(num1) + to_string(num2); 20 | string s2 = to_string(num2) + to_string(num1); 21 | 22 | return s2 < s1; 23 | } 24 | }; 25 | ``` 26 | 27 | ## 使用lambda表达式 28 | 29 | ```c++ 30 | class Solution { 31 | public: 32 | string largestNumber(vector& nums) { 33 | sort(nums.begin(),nums.end(),[](const int &num1,const int &num2){ 34 | return to_string(num2) + to_string(num1) < to_string(num1) + to_string(num2); 35 | }); 36 | 37 | //处理所有元素都是0的情况 38 | if(!nums.empty() && nums[0] == 0) return "0"; 39 | 40 | string res = ""; 41 | for(int num : nums) res = res + to_string(num); 42 | 43 | return res; 44 | } 45 | }; 46 | ``` 47 | -------------------------------------------------------------------------------- /189.Rotate Array/189.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void rotate(vector& nums, int k) { 4 | k = k % nums.size(); 5 | if(k == 0) return; 6 | int sz = nums.size(); 7 | int l = 0,r = sz - 1; 8 | while(l < r) { swap(nums[l++],nums[r--]);} 9 | l = 0,r = k - 1; 10 | while(l < r) {swap(nums[l++],nums[r--]);} 11 | l = k,r = sz - 1; 12 | while(l < r) {swap(nums[l++],nums[r--]);} 13 | } 14 | }; -------------------------------------------------------------------------------- /189.Rotate Array/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 4 | 5 | 示例 1: 6 | 7 | ``` 8 | 输入: [1,2,3,4,5,6,7] 和 k = 3 9 | 输出: [5,6,7,1,2,3,4] 10 | 解释: 11 | 向右旋转 1 步: [7,1,2,3,4,5,6] 12 | 向右旋转 2 步: [6,7,1,2,3,4,5] 13 | 向右旋转 3 步: [5,6,7,1,2,3,4] 14 | ```` 15 | 16 | 示例 2: 17 | 18 | ``` 19 | 输入: [-1,-100,3,99] 和 k = 2 20 | 输出: [3,99,-1,-100] 21 | 解释: 22 | 向右旋转 1 步: [99,-1,-100,3] 23 | 向右旋转 2 步: [3,99,-1,-100] 24 | ``` 25 | 26 | 说明: 27 | 28 | * 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 29 | * 要求使用空间复杂度为 O(1) 的原地算法。 30 | 31 | ## 解答 32 | 33 | 将数组旋转一次,可以将前面的数和后面k个数交换位置。但这两个区间的数也会反序,因此再对两个区间做一次反序 34 | 35 | ```c++ 36 | class Solution { 37 | public: 38 | void rotate(vector& nums, int k) { 39 | k = k % nums.size(); 40 | if(k == 0) return; 41 | int sz = nums.size(); 42 | int l = 0,r = sz - 1; 43 | while(l < r) { swap(nums[l++],nums[r--]);} 44 | l = 0,r = k - 1; 45 | while(l < r) {swap(nums[l++],nums[r--]);} 46 | l = k,r = sz - 1; 47 | while(l < r) {swap(nums[l++],nums[r--]);} 48 | } 49 | }; 50 | ``` -------------------------------------------------------------------------------- /19.Remove Nth Node From End of List/19.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* removeNthFromEnd(ListNode* head, int n) { 12 | if(n <= 0) return head; 13 | ListNode *prev = head,*behind = head; 14 | n = n + 1;//移动到倒数第n个节点的前一个节点 15 | while(n && prev){ 16 | prev = prev->next; 17 | n--; 18 | } 19 | if(n){ 20 | if(n > 1) return head; //n太大,直接返回 21 | //删除的是头节点 22 | behind = head; 23 | head = head->next; 24 | delete behind; 25 | return head; 26 | } 27 | while(prev){ 28 | prev = prev->next; 29 | behind = behind->next; 30 | } 31 | ListNode *tp = behind->next->next; 32 | delete behind->next ; 33 | behind->next = tp; 34 | return head; 35 | } 36 | }; -------------------------------------------------------------------------------- /190.Reverse Bits/190.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | uint32_t reverseBits(uint32_t n) { 4 | int mask = 1; 5 | uint32_t res = 0; 6 | for(int i = 1;i <= 32;i++){ 7 | res = (res << 1); 8 | if(n & mask) 9 | res |= 1; 10 | mask = mask << 1; 11 | } 12 | return res; 13 | } 14 | }; -------------------------------------------------------------------------------- /190.Reverse Bits/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 颠倒给定的 32 位无符号整数的二进制位。 4 | 5 | 示例: 6 | 7 | ``` 8 | 输入: 43261596 9 | 输出: 964176192 10 | 解释: 43261596 的二进制表示形式为 00000010100101000001111010011100 , 11 | 返回 964176192,其二进制表示形式为 00111001011110000010100101000000 。 12 | ``` 13 | 14 | 进阶: 15 | 16 | 如果多次调用这个函数,你将如何优化你的算法? 17 | 18 | ## 解答 19 | 20 | 结果res初始化为1,假设n的第i比特为1,那么反转后res的第31-i比特为1。因此,如果从右往左处理,n的第i比特为1,因为n还剩31-i比特需要处理,那么每次将res左移1位,最终第31-i比特就是1: 21 | 22 | ```c++ 23 | class Solution { 24 | public: 25 | uint32_t reverseBits(uint32_t n) { 26 | int mask = 1; 27 | uint32_t res = 0; 28 | for(int i = 1;i <= 32;i++){ 29 | res = (res << 1); 30 | if(n & mask) 31 | res |= 1; 32 | mask = mask << 1; 33 | } 34 | return res; 35 | } 36 | }; 37 | ``` 38 | 39 | Discuss里面的一种解答: 40 | 41 | ```c++ 42 | class Solution { 43 | public: 44 | uint32_t reverseBits(uint32_t n) { 45 | n = (n >> 16) | (n << 16); 46 | n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8); 47 | n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4); 48 | n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2); 49 | n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1); 50 | return n; 51 | } 52 | }; 53 | ``` 54 | -------------------------------------------------------------------------------- /191.Number of 1 Bits/191.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int hammingWeight(uint32_t n) { 4 | int count = 0; 5 | while(n){ 6 | count++; 7 | n = n & (n - 1); 8 | } 9 | return count; 10 | } 11 | }; -------------------------------------------------------------------------------- /191.Number of 1 Bits/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 4 | 5 | 示例 : 6 | 7 | ``` 8 | 输入: 11 9 | 输出: 3 10 | 解释: 整数 11 的二进制表示为 00000000000000000000000000001011 11 | ``` 12 | 13 | 示例 2: 14 | 15 | ``` 16 | 输入: 128 17 | 输出: 1 18 | 解释: 整数 128 的二进制表示为 00000000000000000000000010000000 19 | ``` 20 | 21 | ## 解答 22 | 23 | 一个数每次减1可以将最右边为1的位变为0,其余右边所有位变为1,因此```n & (n - 1)```可以消去一个数的最右边为1的位。那么根据这个式子统计1的位数,直到n为0即可: 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | int hammingWeight(uint32_t n) { 29 | int count = 0; 30 | while(n){ 31 | count++; 32 | n = n & (n - 1); 33 | } 34 | return count; 35 | } 36 | }; 37 | ``` -------------------------------------------------------------------------------- /198.House Robber/198.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int rob(vector& nums) { 4 | if(nums.empty()) return 0; 5 | if(nums.size() == 1) return nums[0]; 6 | 7 | vector state(nums.size() + 1,0); 8 | state[nums.size() - 1] = nums[nums.size() - 1]; 9 | for(int i = nums.size() - 2;i >= 0;i--) 10 | state[i] = max(state[i + 1],nums[i] + state[i + 2]); 11 | 12 | return state[0]; 13 | } 14 | }; -------------------------------------------------------------------------------- /198.House Robber/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 4 | 5 | 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 6 | 7 | 示例 1: 8 | 9 | ``` 10 | 输入: [1,2,3,1] 11 | 输出: 4 12 | 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 13 | 偷窃到的最高金额 = 1 + 3 = 4 。 14 | ``` 15 | 16 | 示例 2: 17 | 18 | ``` 19 | 输入: [2,7,9,3,1] 20 | 输出: 12 21 | 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 22 | 偷窃到的最高金额 = 2 + 9 + 1 = 12 。 23 | ``` 24 | 25 | ## 解答 26 | 27 | 动态规划,如果state[i]表示从i和i之后的房屋内能偷窃到的最高金额,那么第i间房屋可以选择偷窃或者不偷窃: 28 | 29 | * 如果偷窃,state[i] = nums[i] + state[i + 2] 30 | * 如果不偷窃,state[i] = state[i + 1]; 31 | 32 | 因此,state[i] = max(nums[i] + state[i + 2],state[i + 1]) 33 | 34 | ```c++ 35 | class Solution { 36 | public: 37 | int rob(vector& nums) { 38 | if(nums.empty()) return 0; 39 | if(nums.size() == 1) return nums[0]; 40 | 41 | vector state(nums.size() + 1,0); 42 | state[nums.size() - 1] = nums[nums.size() - 1]; 43 | for(int i = nums.size() - 2;i >= 0;i--) 44 | state[i] = max(state[i + 1],nums[i] + state[i + 2]); 45 | 46 | return state[0]; 47 | } 48 | }; 49 | ``` 50 | -------------------------------------------------------------------------------- /2.Add Two Numbers/2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { 12 | ListNode preHead(0), *p = &preHead; 13 | int extra = 0; 14 | while (l1 || l2 || extra) { 15 | int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra; 16 | extra = sum / 10; 17 | p->next = new ListNode(sum % 10); 18 | p = p->next; 19 | l1 = l1 ? l1->next : l1; 20 | l2 = l2 ? l2->next : l2; 21 | } 22 | return preHead.next; 23 | } 24 | }; -------------------------------------------------------------------------------- /2.Add Two Numbers/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。 4 | 5 | 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 6 | 7 | 示例: 8 | 9 | ``` 10 | 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 11 | 输出:7 -> 0 -> 8 12 | 原因:342 + 465 = 807 13 | ``` 14 | 15 | ## 解答 16 | 17 | * **可以在新链表头结点之前创建一个辅助节点来便利处理** 18 | * 要注意链表处理完后可能还有进位,此时还需创建一个节点 19 | 20 | ```c++ 21 | /** 22 | * Definition for singly-linked list. 23 | * struct ListNode { 24 | * int val; 25 | * ListNode *next; 26 | * ListNode(int x) : val(x), next(NULL) {} 27 | * }; 28 | */ 29 | class Solution { 30 | public: 31 | ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { 32 | ListNode preHead(0), *p = &preHead; 33 | int extra = 0; 34 | while (l1 || l2 || extra) { 35 | int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra; 36 | extra = sum / 10; 37 | p->next = new ListNode(sum % 10); 38 | p = p->next; 39 | l1 = l1 ? l1->next : l1; 40 | l2 = l2 ? l2->next : l2; 41 | } 42 | return preHead.next; 43 | } 44 | }; 45 | ``` -------------------------------------------------------------------------------- /20.Valid Parentheses/20.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isValid(string s) { 4 | stack stack; 5 | for(int i = 0;i < s.length();i++){ 6 | switch(s[i]){ 7 | case ')': 8 | if(stack.empty() || stack.top() != '(') 9 | return false; 10 | stack.pop(); 11 | break; 12 | case '}': 13 | if(stack.empty() || stack.top() != '{') 14 | return false; 15 | stack.pop(); 16 | break; 17 | case ']': 18 | if(stack.empty() || stack.top() != '[') 19 | return false; 20 | stack.pop(); 21 | break; 22 | default: 23 | stack.push(s[i]); 24 | break; 25 | } 26 | } 27 | return stack.empty() ? true : false; 28 | } 29 | }; -------------------------------------------------------------------------------- /200.Number of Islands/200.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numIslands(vector>& grid) { 4 | int count = 0; 5 | for(int row = 0;row < grid.size();row++){ 6 | for(int col = 0;col < grid[0].size();col++){ 7 | if(grid[row][col] == '1'){ 8 | count++; 9 | dfs(grid,row,col); 10 | } 11 | } 12 | } 13 | /* 如果不想改动grid,可以将所有的'#'变回'1' 14 | for(int row = 0;row < grid.size();row++){ 15 | for(int col = 0;col < grid[0].size();col++){ 16 | if(grid[row][col] == '#'){ 17 | grid[row][col] = '1'; 18 | } 19 | } 20 | } 21 | */ 22 | return count; 23 | } 24 | 25 | private: 26 | void dfs(vector>& grid,int row,int col){ 27 | if(row < 0 || col < 0 || row >= grid.size() || col >= grid[0].size() || grid[row][col] != '1') return; 28 | //没越界,并且为'1' 29 | grid[row][col] = '#'; 30 | dfs(grid,row - 1,col); 31 | dfs(grid,row + 1,col); 32 | dfs(grid,row,col - 1); 33 | dfs(grid,row,col + 1); 34 | } 35 | }; -------------------------------------------------------------------------------- /202.Happy Number/202.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isHappy(int n) { 4 | while(n>6){ 5 | int next = 0; 6 | while(n){next+=(n%10)*(n%10); n/=10;} 7 | n = next; 8 | } 9 | return n==1; 10 | } 11 | }; -------------------------------------------------------------------------------- /202.Happy Number/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 编写一个算法来判断一个数是不是“快乐数”。 4 | 5 | 一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。 6 | 7 | 示例: 8 | 9 | ``` 10 | 输入: 19 11 | 输出: true 12 | 解释: 13 | 1^2 + 9^2 = 82 14 | 8^2 + 2^2 = 68 15 | 6^2 + 8^2 = 100 16 | 1^2 + 0^2 + 0^2 = 1 17 | ``` 18 | 19 | ## 解答 20 | 21 | ### 方法一:利用辅助空间 22 | 23 | 可以使用一个set存储已经处理过的数,下一个数存在于set中,说明出现了重复,那么会进入无限循环,因此返回false: 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | bool isHappy(int n) { 29 | if(n <= 0) return false; 30 | if(n == 1) return true; 31 | 32 | unordered_set s; 33 | s.insert(n); 34 | 35 | int next = 0; 36 | while(n){ 37 | int digit = n % 10; 38 | next += digit * digit; 39 | n = n /10; 40 | if(n == 0){ 41 | if(next == 1) return true; 42 | if(s.find(next) != s.end()) return false; 43 | s.insert(next); 44 | n = next; 45 | next = 0; 46 | } 47 | } 48 | 49 | return false; 50 | } 51 | }; 52 | ``` 53 | 54 | ### 方法二:不需要辅助空间 55 | 56 | 1\~6中,只有1是“快乐数”,因此,计算直到下一个数落在1~6的范围内,然后如果是1就返回true,否则返回false: 57 | 58 | ```c++ 59 | class Solution { 60 | public: 61 | bool isHappy(int n) { 62 | while(n>6){ 63 | int next = 0; 64 | while(n){next+=(n%10)*(n%10); n/=10;} 65 | n = next; 66 | } 67 | return n==1; 68 | } 69 | }; 70 | ``` -------------------------------------------------------------------------------- /203.Remove Linked List Elements/203.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* removeElements(ListNode* head, int val) { 12 | ListNode *tp,**curr = &head; 13 | 14 | while(*curr){ 15 | if((*curr)->val == val){ 16 | tp = *curr; 17 | *curr = (*curr) -> next; 18 | tp -> next = NULL; 19 | delete tp; 20 | } 21 | else 22 | curr = &((*curr) -> next); 23 | } 24 | 25 | return head; 26 | } 27 | }; -------------------------------------------------------------------------------- /203.Remove Linked List Elements/README.md: -------------------------------------------------------------------------------- 1 | ## 思路 2 | 3 | 用指针的指针curr进行删除,用临时指针tp记录需要删除的节点 4 | 5 | 当节点不应该删除时,修改curr指向后续节点中的next成员 6 | 7 | ### 复杂度分析 8 | 9 | * 时间复杂度:O(n) 10 | * 空间复杂度:O(1) 11 | -------------------------------------------------------------------------------- /204.Count Primes/204.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int countPrimes(int n) { 4 | if(n <= 2) return 0; 5 | 6 | bool *state = new bool[n]; 7 | for(int i = 0;i < n;i++) state[i] = true; 8 | state[0] = false; 9 | state[1] = false; 10 | for(int i = 2;i * i < n;i++) 11 | if(state[i]) 12 | for(int j = i;i * j < n;j++) 13 | state[i * j] = false; 14 | 15 | 16 | int count = 0; 17 | for(int i = 2;i < n;i++) 18 | if(state[i]) 19 | count++; 20 | return count; 21 | } 22 | }; -------------------------------------------------------------------------------- /204.Count Primes/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 统计所有小于非负整数 n 的质数的数量。 4 | 5 | 示例: 6 | 7 | ``` 8 | 输入: 10 9 | 输出: 4 10 | 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。 11 | ``` 12 | 13 | ## 解答 14 | 15 | 创建一个bool数组state,[0,n)中非负数标位false,最后统计数组中为true的数量,即质数的数量 16 | 17 | 一个质数只能被1和该数本身整除,那么: 18 | 19 | ``` 20 | 2*2,2*3,2*4,... //4,6,8,... 21 | 3*3,3*4,3*5,... //9,12,15,... 22 | 4*4,4*5,4*6,... //16,20,24,... 23 | ... 24 | ``` 25 | 26 | 都不是质数,因此,只需要设变量i为2\~m(i\*inext; 21 | curr->next = prev; 22 | prev = curr; 23 | curr = next; 24 | } 25 | 26 | return prev; 27 | } 28 | }; 29 | 30 | /* 31 | 递归版 32 | */ 33 | 34 | class Solution { 35 | public: 36 | ListNode* reverseList(ListNode* head) { 37 | if(head == NULL || head->next == NULL) return head; 38 | 39 | ListNode* p = reverseList(head->next); 40 | 41 | head->next->next = head; 42 | head->next = NULL; 43 | 44 | return p; 45 | } 46 | }; -------------------------------------------------------------------------------- /206.Reverse Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## Solution 2 | 3 | ### Approach #1(迭代) 4 | 5 | 每次循环将curr.next修改为前一节点 6 | 7 | 因为需要将当前节点的next节点修改为前一节点,所以需要用一个指针prev记录前一节点。同时,由于修改了当前节点的next节点后,无法访问原来的next节点,因此需要一个指针next,在修改前记录原来的next节点 8 | 9 | #### 复杂度分析 10 | 11 | * 时间复杂度:O(n) 12 | * 空间复杂度:O(1) 13 | 14 | ### Approach #2(递归) 15 | 16 | ``` 17 | n(1) -> n(2) -> ... -> n(k) -> n(k+1) <- ... <- n(m) 18 | ``` 19 | 20 | 在m个节点的链表中,对于每次递归处理的节点k,假设节点k之后的节点已经处理完(逆序)。对于节点k,只需修改其next成员,以及节点(k+1)的next成员 21 | 22 | ``` 23 | n(k)->next->next = n(k); 24 | n(k)->next = NULL; 25 | ``` 26 | 27 | 函数返回逆序后链表的头结点,因此对于n(m),直接返回n(m) 28 | 29 | #### 复杂度分析 30 | 31 | * 时间复杂度:O(n) 32 | * 空间复杂度:O(n)(每次递归函数栈帧都会创建1个局部指针保存逆序后的链表头结点) 33 | 34 | >注:不能假设对于每次递归处理的节点k,前k-1个节点已经逆序。因为节点k无法访问到前一节点,因此无法将k节点逆序,因此对于节点k+1,前k个节点无法逆序。也不能假设前k个节点已经逆序,因为如果前k个节点已经逆序,对于节点k,将k+1节点逆序,当处理k+1节点时,无法访问到k+2节点 -------------------------------------------------------------------------------- /207.Course Schedule/207.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canFinish(int numCourses, vector>& prerequisites) { 4 | vector > graph(numCourses); 5 | vector indegrees(numCourses,0); //顶点的入度,即有多少边指向该顶点 6 | 7 | for(auto p : prerequisites){ 8 | indegrees[p.first]++; 9 | graph[p.second].push_back(p.first); 10 | } 11 | 12 | deque q; 13 | for(int v = 0;v < numCourses;v++) 14 | if(indegrees[v] == 0) 15 | q.push_back(v); 16 | while(!q.empty()){ 17 | int v = q.front(); 18 | q.pop_front(); 19 | for(int v2 : graph[v]) 20 | if(--indegrees[v2] == 0) 21 | q.push_back(v2); 22 | } 23 | 24 | for(int indegree : indegrees) 25 | if(indegree) 26 | return false; 27 | return true; 28 | } 29 | }; -------------------------------------------------------------------------------- /21.Merge Two Sorted Lists/21.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 12 | ListNode *head,*p,*tp,**curr; 13 | 14 | if(l1 == NULL) return l2; 15 | else if(l2 == NULL) return l1; 16 | 17 | if(l1->val <= l2->val) {head = l1;p = l2;} 18 | else {head = l2;p = l1;} 19 | 20 | curr = &head; 21 | while(p != NULL){ 22 | while(*curr != NULL && (*curr)->val <= p->val) curr = &((*curr)->next); 23 | //循环结束时,已经遍历完一个链表或者当前链表下一个元素更大,需要插入 24 | tp = *curr; 25 | *curr = p; 26 | p = tp; 27 | } 28 | 29 | return head; 30 | } 31 | }; -------------------------------------------------------------------------------- /21.Merge Two Sorted Lists/README.md: -------------------------------------------------------------------------------- 1 | ## 思路 2 | 3 | 首先判断空链表的情况,如果存在一个链表为空,则直接返回另一链表 4 | 5 | 如果两个链表都不为空,首先获取最终链表的head节点:如果l1的head节点更小,则使用l1的head节点作为最终链表的head节点。否则使用l2的head节点 6 | 7 | ![](../img/21-1.png) 8 | 9 | 然后从head节点开始遍历,查找第一个比另一链表“未处理节点中首节点”大的节点,如果没有则会遍历完head节点所在的链表。然后将另一链表“未处理节点中首节点”插入。用一个指针p记录插入前链表剩余部分的首节点。一直重复此步骤直到其中一个链表的“未处理节点”为空(表示这个链表的所有节点已经插入到另一个链表中): 10 | 11 | ![](../img/21-2.png) 12 | 13 | 由于每个节点至多访问一次,所以时间代价为n -------------------------------------------------------------------------------- /210.Course Schedule II/210.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector findOrder(int numCourses, vector>& prerequisites) { 4 | vector > graph(numCourses); 5 | vector indegrees(numCourses,0); //顶点的入度,即有多少边指向该顶点 6 | vector res; 7 | 8 | for(auto p : prerequisites){ 9 | indegrees[p.first]++; 10 | graph[p.second].push_back(p.first); 11 | } 12 | 13 | deque q; 14 | for(int v = 0;v < numCourses;v++) 15 | if(indegrees[v] == 0){ 16 | q.push_back(v); 17 | res.push_back(v); 18 | } 19 | while(!q.empty()){ 20 | int v = q.front(); 21 | q.pop_front(); 22 | for(int v2 : graph[v]) 23 | if(--indegrees[v2] == 0){ 24 | q.push_back(v2); 25 | res.push_back(v2); 26 | } 27 | } 28 | 29 | for(int indegree : indegrees) 30 | if(indegree) 31 | return vector(); 32 | return res; 33 | } 34 | }; -------------------------------------------------------------------------------- /215.Kth Largest Element in an Array/215.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findKthLargest(vector& nums, int k) { 4 | vector min(nums.begin(),nums.begin() + k); 5 | make_heap(min.begin(),min.end(),greater()); 6 | 7 | for(int i = k;i < nums.size();i++){ 8 | if(nums[i] > min.front()){ 9 | pop_heap(min.begin(),min.end(),greater()); 10 | min.pop_back(); 11 | min.push_back(nums[i]); 12 | push_heap(min.begin(),min.end(),greater()); 13 | } 14 | } 15 | 16 | return min.front(); 17 | } 18 | }; -------------------------------------------------------------------------------- /215.Kth Largest Element in an Array/README.md: -------------------------------------------------------------------------------- 1 | ## 基于最小堆 2 | 3 | ```c++ 4 | class Solution { 5 | public: 6 | int findKthLargest(vector& nums, int k) { 7 | vector min(nums.begin(),nums.begin() + k); 8 | make_heap(min.begin(),min.end(),greater()); 9 | 10 | for(int i = k;i < nums.size();i++){ 11 | if(nums[i] > min.front()){ 12 | pop_heap(min.begin(),min.end(),greater()); 13 | min.pop_back(); 14 | min.push_back(nums[i]); 15 | push_heap(min.begin(),min.end(),greater()); 16 | } 17 | } 18 | 19 | return min.front(); 20 | } 21 | }; 22 | ``` 23 | 24 | ## 基于partition 25 | 26 | ```c++ 27 | class Solution { 28 | public: 29 | int findKthLargest(vector& nums, int k) { 30 | int idx = -1,target = nums.size() - k,l = 0,r = nums.size() - 1; 31 | 32 | while(idx != target){ 33 | idx = partition(nums,l,r); 34 | if(idx < target) l = idx + 1; 35 | else if(idx > target) r = idx - 1; 36 | } 37 | 38 | return nums[target]; 39 | } 40 | private: 41 | int partition(vector &nums,int l,int r){ 42 | int pivot = nums[r]; 43 | int i = l - 1; 44 | for(int j = l;j < r;j++){ 45 | if(nums[j] < pivot){ 46 | int tp = nums[++i]; 47 | nums[i] = nums[j]; 48 | nums[j] = tp; 49 | } 50 | } 51 | nums[r] = nums[++i]; 52 | nums[i] = pivot; 53 | return i; 54 | } 55 | }; 56 | ``` -------------------------------------------------------------------------------- /217.Contains Duplicate/217.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool containsDuplicate(vector& nums) { 4 | return nums.size() > set(nums.begin(), nums.end()).size(); 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /217.Contains Duplicate/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个整数数组,判断是否存在重复元素。 4 | 5 | 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 6 | 7 | 示例 1: 8 | 9 | ``` 10 | 输入: [1,2,3,1] 11 | 输出: true 12 | ``` 13 | 14 | 示例 2: 15 | 16 | ``` 17 | 输入: [1,2,3,4] 18 | 输出: false 19 | ``` 20 | 21 | 示例 3: 22 | 23 | ``` 24 | 输入: [1,1,1,3,3,4,3,2,4,2] 25 | 输出: true 26 | ``` 27 | 28 | ## 解答 29 | 30 | 使用一个set存储元素,如果某个元素在set中,说明出现重复 31 | 32 | ```c++ 33 | class Solution { 34 | public: 35 | bool containsDuplicate(vector& nums) { 36 | unordered_set s; 37 | for(int e : nums){ 38 | if(s.find(e) != s.end()) 39 | return true; 40 | else 41 | s.insert(e); 42 | } 43 | return false; 44 | } 45 | }; 46 | ``` 47 | 48 | Discuss中一行的方法: 49 | 50 | ```c++ 51 | class Solution { 52 | public: 53 | bool containsDuplicate(vector& nums) { 54 | return nums.size() > set(nums.begin(), nums.end()).size(); 55 | } 56 | }; 57 | 58 | ``` -------------------------------------------------------------------------------- /22.Generate Parentheses/22.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector generateParenthesis(int n) { 4 | if(n <= 0) 5 | return vector(); 6 | 7 | vector res; 8 | string s; 9 | generateParenthesis(s,n,n,res); 10 | return res; 11 | } 12 | 13 | private: 14 | void generateParenthesis(string s,int left,int right, vector &res){ 15 | if(!left && !right){ 16 | res.push_back(s); 17 | return; 18 | } 19 | 20 | if(left == right) generateParenthesis(s+'(',left-1,right,res); 21 | else if(left == 0) generateParenthesis(s+')',left,right-1,res); 22 | else { 23 | generateParenthesis(s+')',left,right-1,res); 24 | generateParenthesis(s+'(',left-1,right,res); 25 | } 26 | } 27 | }; -------------------------------------------------------------------------------- /22.Generate Parentheses/README.md: -------------------------------------------------------------------------------- 1 | 2 | * 当'('数量大于')'时,新的字符可以是'('也可以是')'(如果'('已经用完则只能是')') 3 | * 当'('数量等于')'时,新的字符只能是‘(’ 4 | * 当'('数量小于')'时,不是一个有效的结果 5 | 6 | 比方说如果前两个字符是'(',即"((",那么第3个字符可以是'('也可以是')'; 7 | 8 | 如果前两个字符一个是'('和')',即'()',那么第3个字符必须是'(' 9 | 10 | 使用两个变量left和right,分别记录'('剩余数量和')'的剩余数量,根据上述逻辑递归 11 | -------------------------------------------------------------------------------- /227.Basic Calculator II/227.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int calculate(string s) { 4 | deque nums; 5 | deque ops; 6 | 7 | int i = 0; 8 | for(int j = i;j < s.size();j++){ 9 | if(s[j] == '+' || s[j] == '-' || s[j] == '*' || s[j] == '/'){ 10 | int num = stoi(s.substr(i,j - i)); 11 | if(!ops.empty() && (ops.back() == '*' || ops.back() == '/')){ 12 | if(ops.back() == '*') 13 | nums.back() = nums.back() * num; 14 | else 15 | nums.back() = nums.back() / num; 16 | ops.pop_back(); 17 | } 18 | else 19 | nums.push_back(num); 20 | ops.push_back(s[j]); 21 | i = j + 1; 22 | } 23 | } 24 | 25 | nums.push_back(stoi(s.substr(i,s.size() - i)));//最后一个数 26 | if(!ops.empty() && (ops.back() == '*' || ops.back() == '/')){ 27 | int num = nums.back();nums.pop_back(); 28 | if(ops.back() == '*') 29 | nums.back() = nums.back() * num; 30 | else 31 | nums.back() = nums.back() / num; 32 | ops.pop_back(); 33 | } 34 | 35 | while(nums.size() > 1){ 36 | int num = nums.front(); nums.pop_front(); 37 | if(ops.front() == '+') 38 | nums.front() = num + nums.front(); 39 | else if(ops.front() == '-') 40 | nums.front() = num - nums.front(); 41 | ops.pop_front(); 42 | } 43 | 44 | return nums.front(); 45 | } 46 | }; -------------------------------------------------------------------------------- /227.Basic Calculator II/README.md: -------------------------------------------------------------------------------- 1 | 第一次遍历将'\*'和'/'进行计算,使用一个队列保存操作数,一个队列保存操作符 2 | 3 | 第一次遍历完后,如果操作数队列中的数字个数大于1,则按从左往右的顺序计算,因为第一次遍历已经处理了所有乘法和除法,所以现在只需处理加法和减法 -------------------------------------------------------------------------------- /23.Merge k Sorted Lists/23.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* mergeKLists(vector& lists) { 12 | int sz = lists.size(); 13 | if(sz == 0) return NULL; 14 | if(sz == 1) return lists[0]; 15 | 16 | vector mergeLists; 17 | for(int i = 0;i < sz - 1;i += 2){ 18 | ListNode *l1 = lists[i],*l2 = lists[i + 1]; 19 | ListNode *mergelist = l1 && l2 ? NULL : (l1 ? l1 : l2),*curr = NULL; 20 | while(l1 && l2){ 21 | ListNode *next; 22 | if(l1->val < l2->val){ 23 | next = l1; 24 | l1 = l1->next; 25 | }else{ 26 | next = l2; 27 | l2 = l2->next; 28 | } 29 | if(!mergelist){ 30 | mergelist = next; 31 | curr = next; 32 | } 33 | else{ 34 | curr->next = next; 35 | curr = curr->next; 36 | } 37 | } 38 | if(curr && l1) curr->next = l1; 39 | else if(curr && l2) curr->next = l2; 40 | mergeLists.push_back(mergelist); 41 | } 42 | 43 | if(sz % 2) mergeLists.push_back(lists[sz - 1]); 44 | 45 | return mergeKLists(mergeLists); 46 | } 47 | }; -------------------------------------------------------------------------------- /230.Kth Smallest Element in a BST/230.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int kthSmallest(TreeNode* root, int k) { 4 | if(!root || k < 0) return -1; 5 | 6 | stack s; 7 | TreeNode *curr = root; 8 | while(curr || !s.empty()){ 9 | if(curr){ 10 | s.push(curr); 11 | curr = curr->left; 12 | } 13 | else{ 14 | TreeNode *nd = s.top(); 15 | if(k == 1) return nd->val; 16 | s.pop();k--; 17 | curr = nd->right; 18 | } 19 | } 20 | 21 | return -1;//k大于BST的节点总数 22 | } 23 | }; -------------------------------------------------------------------------------- /230.Kth Smallest Element in a BST/README.md: -------------------------------------------------------------------------------- 1 | ```c++ 2 | /** 3 | * Definition for a binary tree node. 4 | * struct TreeNode { 5 | * int val; 6 | * TreeNode *left; 7 | * TreeNode *right; 8 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 9 | * }; 10 | */ 11 | ``` 12 | 13 | ## 递归版 14 | 15 | ```c++ 16 | class Solution { 17 | public: 18 | int kthSmallest(TreeNode* root, int k) { 19 | if(!root || k < 0) return -1; 20 | 21 | int res; 22 | preOrderTraversal(root,k,res); 23 | 24 | return res; 25 | } 26 | private: 27 | void preOrderTraversal(TreeNode *node,int &k,int &res){ 28 | if(!node) return; 29 | 30 | preOrderTraversal(node->left,k,res); 31 | if(k == 0) return; 32 | if(--k == 0) res = node->val; 33 | else preOrderTraversal(node->right,k,res); 34 | } 35 | }; 36 | ``` 37 | 38 | ## 迭代版 39 | 40 | ```c++ 41 | class Solution { 42 | public: 43 | int kthSmallest(TreeNode* root, int k) { 44 | if(!root || k < 0) return -1; 45 | 46 | stack s; 47 | TreeNode *curr = root; 48 | while(curr || !s.empty()){ 49 | if(curr){ 50 | s.push(curr); 51 | curr = curr->left; 52 | } 53 | else{ 54 | TreeNode *nd = s.top(); 55 | if(k == 1) return nd->val; 56 | s.pop();k--; 57 | curr = nd->right; 58 | } 59 | } 60 | 61 | return -1;//k大于BST的节点总数 62 | } 63 | }; 64 | ``` -------------------------------------------------------------------------------- /234.Palindrome Linked List/234.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | bool isPalindrome(ListNode* head) { 12 | if(!head) return true; 13 | 14 | ListNode *b = head,*e = NULL; 15 | return isPalindrome(head,&b,&e); 16 | } 17 | 18 | private: 19 | bool isPalindrome(ListNode* node,ListNode **b,ListNode **e){ 20 | if(node->next) 21 | if(!isPalindrome(node->next,b,e)) 22 | return false; 23 | 24 | if(*b == *e) 25 | return true; 26 | *e = node; 27 | if((*b)->val == (*e)->val){ 28 | (*b) = (*b)->next; 29 | return true; 30 | } 31 | else 32 | return false; 33 | } 34 | }; -------------------------------------------------------------------------------- /234.Palindrome Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 请判断一个链表是否为回文链表。 4 | 5 | 示例 1: 6 | 7 | ``` 8 | 输入: 1->2 9 | 输出: false 10 | ``` 11 | 12 | 示例 2: 13 | 14 | ``` 15 | 输入: 1->2->2->1 16 | 输出: true 17 | ``` 18 | 19 | 进阶: 20 | 21 | 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 22 | 23 | ## 解答 24 | 25 | 使用两个指针b和e,b指向链表的头节点,e指向链表的尾节点,如果b和e的值相等,那么b指向下一个节点,e指向前一个节点,直到b和e指向相同节点。关键是链表单向,因此使用递归来设置e: 26 | 27 | ```c++ 28 | /** 29 | * Definition for singly-linked list. 30 | * struct ListNode { 31 | * int val; 32 | * ListNode *next; 33 | * ListNode(int x) : val(x), next(NULL) {} 34 | * }; 35 | */ 36 | class Solution { 37 | public: 38 | bool isPalindrome(ListNode* head) { 39 | if(!head) return true; 40 | 41 | ListNode *b = head,*e = NULL; 42 | return isPalindrome(head,&b,&e); 43 | } 44 | 45 | private: 46 | bool isPalindrome(ListNode* node,ListNode **b,ListNode **e){ 47 | if(node->next) 48 | if(!isPalindrome(node->next,b,e)) 49 | return false; 50 | 51 | if(*b == *e) 52 | return true; 53 | *e = node; 54 | if((*b)->val == (*e)->val){ 55 | (*b) = (*b)->next; 56 | return true; 57 | } 58 | else 59 | return false; 60 | } 61 | }; 62 | ``` -------------------------------------------------------------------------------- /236.Lowest Common Ancestor of a Binary Tree/236.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 13 | if(!root || !p || !q) return NULL; 14 | if(p == q) return p; 15 | 16 | vector> paths; 17 | vector path; 18 | 19 | preOrderTraversal(root,p,q,paths,path); 20 | 21 | if(paths.size() != 2) return NULL; 22 | 23 | int i = 0,j = 0; 24 | while(paths[0][i + 1] == paths[1][j + 1]) i++,j++; 25 | 26 | return paths[0][i]; 27 | } 28 | private: 29 | void preOrderTraversal(TreeNode *root,TreeNode *p,TreeNode *q, 30 | vector> &paths,vector &path) 31 | { 32 | if(!root) return; 33 | 34 | path.push_back(root); 35 | if(root == p) paths.push_back(path); 36 | else if(root == q) paths.push_back(path); 37 | if(root->left) preOrderTraversal(root->left,p,q,paths,path); 38 | if(root->right) preOrderTraversal(root->right,p,q,paths,path); 39 | path.pop_back(); 40 | } 41 | }; -------------------------------------------------------------------------------- /236.Lowest Common Ancestor of a Binary Tree/README.md: -------------------------------------------------------------------------------- 1 | 因为节点没有指向父节点的指针,所以先使用前序遍历遍历二叉树,保存从根节点到两个节点的两条路径 2 | 3 | 然后问题转化成找出两条路径最后一个相同的节点 -------------------------------------------------------------------------------- /237.Delete Node in a Linked List/237.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | void deleteNode(ListNode* node) { 12 | ListNode *tp = node->next; 13 | node->val = tp->val; 14 | node->next = tp->next; 15 | delete tp; 16 | } 17 | }; -------------------------------------------------------------------------------- /237.Delete Node in a Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 请编写一个函数,使其可以删除某个链表中给定的(非末尾的)节点,您将只被给予要求被删除的节点 4 | 5 | 比如:假设该链表为 1 -> 2 -> 3 -> 4 ,给定您的为该链表中值为 3 的第三个节点,那么在调用了您的函数之后,该链表则应变成 1 -> 2 -> 4 6 | 7 | ## 解答 8 | 9 | 将下一个节点的值复制过来,然后删除下一个节点: 10 | 11 | ```c++ 12 | /** 13 | * Definition for singly-linked list. 14 | * struct ListNode { 15 | * int val; 16 | * ListNode *next; 17 | * ListNode(int x) : val(x), next(NULL) {} 18 | * }; 19 | */ 20 | class Solution { 21 | public: 22 | void deleteNode(ListNode* node) { 23 | ListNode *tp = node->next; 24 | node->val = tp->val; 25 | node->next = tp->next; 26 | delete tp; 27 | } 28 | }; 29 | ``` -------------------------------------------------------------------------------- /238.Product of Array Except Self/238.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector productExceptSelf(vector& nums) { 4 | if(nums.size() <= 1) return vector(); 5 | 6 | vector res(nums.size(),0); 7 | res[0] = 1; 8 | for(int i = 1;i < nums.size();i++){ 9 | res[i] = res[i - 1] * nums[i - 1]; 10 | } 11 | 12 | int product = 1; 13 | for(int i = nums.size() - 2;i >=0;i--){ 14 | product *= nums[i + 1]; 15 | res[i] *= product; 16 | } 17 | 18 | return res; 19 | } 20 | }; -------------------------------------------------------------------------------- /238.Product of Array Except Self/README.md: -------------------------------------------------------------------------------- 1 | 对于每个元素,该元素将用于求积的元素分为左半部分和右半部分 2 | 3 | 第一次遍历时,求左半部分元素的乘积 4 | 5 | 第二次遍历时,求右半部分元素的乘积,并且和相应的左半部分元素的乘积相乘 -------------------------------------------------------------------------------- /239.Sliding Window Maximum/239.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector maxSlidingWindow(vector& nums, int k) { 4 | if(nums.empty() || k <= 0) return vector(); 5 | 6 | vector res; 7 | deque max_deque; 8 | 9 | for(int i = 0;i < nums.size();i++){ 10 | while(!max_deque.empty() && nums[i] > nums[max_deque.back()]) {max_deque.pop_back();} 11 | max_deque.push_back(i); 12 | if(i - max_deque.front() + 1 > k) max_deque.pop_front(); 13 | if(i >= k - 1) 14 | res.push_back(nums[max_deque.front()]); 15 | } 16 | return res; 17 | } 18 | }; -------------------------------------------------------------------------------- /239.Sliding Window Maximum/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口 k 内的数字。滑动窗口每次只向右移动一位。 4 | 5 | 返回滑动窗口最大值。 6 | 7 | 示例: 8 | 9 | ``` 10 | 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 11 | 输出: [3,3,5,5,6,7] 12 | 解释: 13 | 14 | 滑动窗口的位置 最大值 15 | --------------- ----- 16 | [1 3 -1] -3 5 3 6 7 3 17 | 1 [3 -1 -3] 5 3 6 7 3 18 | 1 3 [-1 -3 5] 3 6 7 5 19 | 1 3 -1 [-3 5 3] 6 7 5 20 | 1 3 -1 -3 [5 3 6] 7 6 21 | 1 3 -1 -3 5 [3 6 7] 7 22 | ``` 23 | 24 | 注意: 25 | 26 | 你可以假设 k 总是有效的,1 ≤ k ≤ 输入数组的大小,且输入数组不为空。 27 | 28 | 进阶: 29 | 30 | 你能在线性时间复杂度内解决此题吗? 31 | 32 | ## 解答 33 | 34 | 使用一个两端队列,队列头部始终保存当前滑动窗口最大值 35 | 36 | 对于数组中任意元素,从尾部向前比较,如果该元素大于尾部元素,则从队列尾部删除,一直删除完所有比新元素小的元素,然后从尾部插入新元素(的下标)。由于新元素不一定比首元素大,如果首元素刚好从滑动窗口移除时,也要删除首元素,所以在完成上述操作后,也要判断首元素是否已经脱离滑动窗口因为要判断队首元素是否脱离滑动窗口,所以队列存的是元素的下标,同时要从首部删除,所以使用双端队列 37 | 38 | 当遍历到数组的第k个元素开始,后面每遍历一个元素时,经过上述处理后,就根据队列首部最大值的下标找到最大值,然后添加到结果中 39 | 40 | ```c++ 41 | class Solution { 42 | public: 43 | vector maxSlidingWindow(vector& nums, int k) { 44 | if(nums.empty() || k <= 0) return vector(); 45 | 46 | vector res; 47 | deque max_deque; 48 | 49 | for(int i = 0;i < nums.size();i++){ 50 | while(!max_deque.empty() && nums[i] > nums[max_deque.back()]) {max_deque.pop_back();} 51 | max_deque.push_back(i); 52 | if(i - max_deque.front() + 1 > k) max_deque.pop_front(); 53 | if(i >= k - 1) 54 | res.push_back(nums[max_deque.front()]); 55 | } 56 | return res; 57 | } 58 | }; 59 | ``` -------------------------------------------------------------------------------- /24.Swap Nodes in Pairs/24.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* swapPairs(ListNode* head) { 12 | ListNode *prev = nullptr,*curr = head; 13 | 14 | while(curr && curr->next){ 15 | if(prev){ 16 | prev->next = curr->next; 17 | curr->next = curr->next->next; 18 | prev->next->next = curr; 19 | } 20 | else{ 21 | prev = curr->next; 22 | curr->next = prev->next; 23 | prev->next = curr; 24 | head = prev; 25 | } 26 | 27 | prev = curr; 28 | curr = curr->next; 29 | } 30 | 31 | return head; 32 | } 33 | }; -------------------------------------------------------------------------------- /24.Swap Nodes in Pairs/README.md: -------------------------------------------------------------------------------- 1 | 两个两个节点进行处理,对于当前节点curr,如果有下一个节点,则进行交换。注意两点: 2 | * 交换后,curr为当前处理两个节点的后一个节点,所以下一次处理前,curr只需往后移动1次 3 | * 下一次处理时,curr可能为空,所以循环要先判断curr是否为空 4 | 5 | ![](../img/24.png) -------------------------------------------------------------------------------- /240.Search a 2D Matrix II/240.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool searchMatrix(vector>& matrix, int target) { 4 | if(matrix.empty()) return false; 5 | 6 | int rows = matrix.size() , cols = matrix[0].size(); 7 | int row = 0,col = cols - 1; 8 | while(row <= rows - 1 && col >= 0){ 9 | if(matrix[row][col] < target) row++; 10 | else if(matrix[row][col] > target) col--; 11 | else return true; 12 | } 13 | 14 | return false; 15 | } 16 | }; -------------------------------------------------------------------------------- /240.Search a 2D Matrix II/README.md: -------------------------------------------------------------------------------- 1 | 如果是一维矩阵,直接使用二分查找,二分查找每次可以将查找范围缩小到一个子数组中,因此考虑利用这种思想处理 2 | 3 | 如果使用矩阵中间的元素进行判断,那么当中间元素小于target时,target可能出现在上面,也可能出现在左边;当中间元素大于target时,target可能出现在右边或下面;那么就都会出现2种情况,一种情况需要修改row,不好处理 4 | 5 | 可以从右上角或者左下角进行查找,以右上角为例: 6 | 7 | * 如果元素大于target,则删除一行,因为该元素左侧的元素都比该元素小,从而都小于target 8 | * 如果元素小于target,则删除一列,因为该元素下面的元素都比该元素大,从而都大于target 9 | * 如果元素等于target,则返回true 10 | 11 | 以这种方式,每次只需递增row或减小col从而删除一行或一列,最终如果出现越界,说明元素不存在矩阵中 12 | -------------------------------------------------------------------------------- /242.Valid Anagram/242.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isAnagram(string s, string t) { 4 | unordered_map map; 5 | for(char c : s) 6 | map[c]++; 7 | 8 | for(char c : t){ 9 | if(map[c] == 0) return false; 10 | else map[c]--; 11 | } 12 | 13 | for(auto p : map) 14 | if(p.second > 0) 15 | return false; 16 | 17 | return true; 18 | } 19 | }; -------------------------------------------------------------------------------- /242.Valid Anagram/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。 4 | 5 | 示例 1: 6 | 7 | ``` 8 | 输入: s = "anagram", t = "nagaram" 9 | 输出: true 10 | ``` 11 | 12 | 示例 2: 13 | 14 | ``` 15 | 输入: s = "rat", t = "car" 16 | 输出: false 17 | ``` 18 | 19 | 说明: 20 | 21 | 你可以假设字符串只包含小写字母。 22 | 23 | 进阶: 24 | 25 | 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? 26 | 27 | ## 解答 28 | 29 | ### 方法一 30 | 31 | 将两个字符串按字典序排序,然后判断是否相等 32 | 33 | ### 方法二 34 | 35 | 使用哈希表,统计字符串s中各字符的出现次数,然后遍历字符串t,如果遇到一个s中的字符,则计数减1,如果字符不在s中,则返回false。最终如果哈希表中所有字符的计数都刚好减为0那么就是异位词: 36 | 37 | ```c++ 38 | class Solution { 39 | public: 40 | bool isAnagram(string s, string t) { 41 | unordered_map map; 42 | for(char c : s) 43 | map[c]++; 44 | 45 | for(char c : t){ 46 | if(map[c] == 0) return false; 47 | else map[c]--; 48 | } 49 | 50 | for(auto p : map) 51 | if(p.second > 0) 52 | return false; 53 | 54 | return true; 55 | } 56 | }; 57 | ``` -------------------------------------------------------------------------------- /26.Remove Duplicates from Sorted Array/26.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeDuplicates(vector& nums) { 4 | int i = 0,j = 0; 5 | while(++j < nums.size()){ 6 | if(nums.at(j) != nums.at(i)){ 7 | if(j - i > 1) 8 | nums.at(i + 1) = nums.at(j); 9 | i++; 10 | } 11 | } 12 | return nums.size() == 0 ? 0 : i + 1; 13 | } 14 | }; -------------------------------------------------------------------------------- /26.Remove Duplicates from Sorted Array/README.md: -------------------------------------------------------------------------------- 1 | ## 思路 2 | 3 | 使用2个下标:i,j 4 | 5 | 假设i及i之前的数组无重复元素,j为遍历数组时的下标,若找到一个与i不等的的元素,则将其拷贝到i+1位置,并更新i的值为i+1 6 | 7 | ![](../img/26.png) 8 | 9 | >如果j-i等于1,说明遍历至今仍未出现1个冗余元素,由于j等于i+1,所以不用将j位置的元素拷贝到i+1,序列本身已经有序且无冗余 10 | 11 | #### 复杂度分析 12 | 13 | * 时间复杂度:O(n) 14 | * 空间复杂度:O(1) -------------------------------------------------------------------------------- /268.Missing Number/268.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int missingNumber(vector& nums) { 4 | int missing = nums.size(); 5 | for(int i = 0;i < nums.size();i++) 6 | missing ^= i ^ nums[i]; 7 | return missing; 8 | } 9 | }; -------------------------------------------------------------------------------- /27.Remove Element/27.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int removeElement(vector& nums, int val) { 4 | int count = 0; 5 | for(int i = 0;i < nums.size();i++){ 6 | if(nums[i] == val) count++; 7 | else if(count != 0) nums[i - count] = nums[i]; 8 | } 9 | 10 | return nums.size() - count; 11 | } 12 | }; -------------------------------------------------------------------------------- /27.Remove Element/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 4 | 5 | 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 6 | 7 | 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 给定 nums = [3,2,2,3], val = 3, 13 | 14 | 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 15 | 16 | 你不需要考虑数组中超出新长度后面的元素。 17 | ``` 18 | 19 | 示例 2: 20 | 21 | ``` 22 | 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 23 | 24 | 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 25 | 26 | 注意这五个元素可为任意顺序。 27 | 28 | 你不需要考虑数组中超出新长度后面的元素 29 | ``` 30 | 31 | ## 解答 32 | 33 | 如果值为val的元素有m个,那么相当于所有在val后面的元素都要前移,最终后面留下m个位置 34 | 35 | 遍历数组,每出现一次val时,计数count增加一,如果元素的值不为val,那么前移count步 36 | 37 | ```c++ 38 | class Solution { 39 | public: 40 | int removeElement(vector& nums, int val) { 41 | int count = 0; 42 | for(int i = 0;i < nums.size();i++){ 43 | if(nums[i] == val) count++; 44 | else if(count != 0) nums[i - count] = nums[i]; 45 | } 46 | 47 | return nums.size() - count; 48 | } 49 | }; 50 | ``` -------------------------------------------------------------------------------- /279.Perfect Squares/279.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numSquares(int n) { 4 | vector state(n + 1,INT_MAX); 5 | state[0] = 0; 6 | 7 | for(int i = 1;i <= n;i++){ 8 | int q = sqrt(i); 9 | if(q * q == i) state[i] = 1; 10 | else{ 11 | for(int j = 1;j <= q;j++){ 12 | if(state[i - j * j] + 1 < state[i]) 13 | state[i] = state[i - j * j] + 1; 14 | } 15 | } 16 | } 17 | 18 | return state[n]; 19 | } 20 | }; -------------------------------------------------------------------------------- /279.Perfect Squares/README.md: -------------------------------------------------------------------------------- 1 | 完美平方数:1,4,9,16,25,... 2 | 3 | 求一个数n最少由多少个完美平方数组成,假设q为sqrt(n): 4 | 5 | * 如果这些数里面包含1,那么求出n-1\*1最少由多少个完美平方数组成,然后加1就是结果 6 | * 否则,如果这些数里面包含2,那么求出n-2\*2最少由多少个完美平方数组成,然后加1就是结果 7 | * ... 8 | * 否则,如果这些数里面包含q,那么求出n-q\*q最少由多少个完美平方数组成,然后加1就是结果 9 | 10 | 因此,这是一个动态规划问题。F(n) = min{F(n),F(n-1)+1,F(n-4)+1,...,F(n-q\*q)+1}。如果递归求解会存在重复子问题,因此使用一个数组state保存状态,“从小到大”求出F(1)到F(n),结果就是state[n] -------------------------------------------------------------------------------- /28.Implement strStr/28.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | // 4 | int strStr(string haystack, string needle) { 5 | if(needle.size() == 0) 6 | return 0; 7 | 8 | char c = needle[0]; 9 | int sz1 = haystack.size(),sz2 = needle.size(); 10 | for(int i = 0 ;i <= sz1 - sz2;i++){ 11 | if(haystack[i] == c){ 12 | int j; 13 | for(j = 0;j < sz2;j++){ 14 | if(haystack[i+j] != needle[j]) 15 | break; 16 | } 17 | if(j == needle.size()) 18 | return i; 19 | } 20 | } 21 | 22 | return -1; 23 | } 24 | }; -------------------------------------------------------------------------------- /28.Implement strStr/README.md: -------------------------------------------------------------------------------- 1 | ### 蛮力法 2 | 3 | 假设haystack长度为n, needle长度为m,遍历haystack的前n-m个字符,对于每个字符,如果等于needle的首字符则继续比较 4 | 5 | **时间复杂度**:O(n\*m) 6 | 7 | ### KMP算法 8 | 9 | [KMP算法](https://blog.csdn.net/hyjoker/article/details/51190726) 10 | 11 | **时间复杂度:O(n+m)** -------------------------------------------------------------------------------- /283.Move Zeroes/283.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void moveZeroes(vector& nums) { 4 | int count = 0; 5 | for(int i = 0;i < nums.size();i++){ 6 | if(nums[i] == 0) count++; 7 | else if(count != 0) nums[i - count] = nums[i]; 8 | } 9 | 10 | int end = nums.size() - 1; 11 | while(count--) 12 | nums[end--] = 0; 13 | } 14 | }; -------------------------------------------------------------------------------- /283.Move Zeroes/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 4 | 5 | 示例: 6 | 7 | ``` 8 | 输入: [0,1,0,3,12] 9 | 输出: [1,3,12,0,0] 10 | ``` 11 | 12 | 说明: 13 | 14 | 1. 必须在原数组上操作,不能拷贝额外的数组。 15 | 2. 尽量减少操作次数。 16 | 17 | ## 解答 18 | 19 | 对0计数,遍历到非0数时,根据0的计数决定向前移动多少。最后根据0的计数将数组尾端的相应个数的元素赋值为0 20 | 21 | ```c++ 22 | class Solution { 23 | public: 24 | void moveZeroes(vector& nums) { 25 | int count = 0; 26 | for(int i = 0;i < nums.size();i++){ 27 | if(nums[i] == 0) count++; 28 | else if(count != 0) nums[i - count] = nums[i]; 29 | } 30 | 31 | int end = nums.size() - 1; 32 | while(count--) 33 | nums[end--] = 0; 34 | } 35 | }; 36 | ``` -------------------------------------------------------------------------------- /287.Find the Duplicate Number/287.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int findDuplicate(vector& nums) { 4 | int l = 1,r = nums.size() - 1;//l和r初始化成1和n 5 | while(l < r){ 6 | int mid = (l + r) >> 1; 7 | int count = 0;//小于等于mid的数的个数 8 | for(int i = 0;i < nums.size();i++) 9 | if(nums[i] <= mid) count++; 10 | if(count <= mid) 11 | l = mid + 1; 12 | else if(count > mid) 13 | r = mid; 14 | } 15 | 16 | return l; 17 | } 18 | }; -------------------------------------------------------------------------------- /287.Find the Duplicate Number/README.md: -------------------------------------------------------------------------------- 1 | **题目**:给出包含n+1个元素的数组,所有数字都在1~n范围内,找出数组中冗余的数组 2 | 3 | * 不能修改数组 4 | * 要求O(1)的空间复杂度 5 | * 时间复杂度要小于O(n^2) 6 | * 只有1个元素冗余,但是可能冗余很多次 7 | 8 | **思路**:假设1~n的中间元素是mid,遍历数组: 9 | 10 | * 如果小于等于mid的个数大于mid,说明重复数字出现在1~mid中 11 | * 如果小于等于mid的个数小于等于mid,说明重复数组出现在mid+1~n中 12 | 13 | 每轮需要遍历n+1个元素,但是每次可以将范围缩小一半,因此时间复杂度小于O(n^2) 14 | 15 | ```c++ 16 | class Solution { 17 | public: 18 | int findDuplicate(vector& nums) { 19 | int l = 1,r = nums.size() - 1;//l和r初始化成1和n 20 | while(l < r){ 21 | int mid = (l + r) >> 1; 22 | int count = 0;//小于等于mid的数的个数 23 | for(int i = 0;i < nums.size();i++) 24 | if(nums[i] <= mid) count++; 25 | if(count <= mid) 26 | l = mid + 1; 27 | else if(count > mid) 28 | r = mid; 29 | } 30 | 31 | return l; 32 | } 33 | }; 34 | ``` 35 | 36 | 去掉一个条件,如果可以修改数组,那么遍历数组中的每个数num,如果num不等于当前下标加1。那么将这个数与下标为num - 1的数交换,直到num等于当前下标加1。如果num - 1位置的数和num相等,表示出现重复,因此返回num 37 | 38 | ```c++ 39 | class Solution { 40 | public: 41 | int findDuplicate(vector& nums) { 42 | for(int i = 0;i < nums.size();i++){ 43 | int tp; 44 | while(nums[i] != i + 1){ 45 | if(nums[nums[i] - 1] != nums[i]){ 46 | tp = nums[nums[i] - 1]; 47 | nums[nums[i] - 1] = nums[i]; 48 | nums[i] = tp; 49 | } 50 | else 51 | return nums[i]; 52 | } 53 | } 54 | 55 | return -1;//输入数据无效 56 | } 57 | }; 58 | ``` 59 | -------------------------------------------------------------------------------- /289.Game of Life/289.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void gameOfLife(vector>& board) { 4 | if(board.empty()) return; 5 | 6 | int rows = board.size(),cols = board[0].size(); 7 | for(int i = 0;i < rows;i++){ 8 | for(int j = 0;j < cols;j++){ 9 | int count = board[i][j] & 1 == 1 ? -1 : 0; 10 | for(int m = max(i - 1,0);m <= min(i + 1,rows - 1);m++) 11 | for(int n = max(j - 1,0);n <= min(j + 1,cols - 1);n++) 12 | if(board[m][n] & 1 == 1) count++; 13 | if(count == 3 || (board[i][j] == 1 && count == 2)) 14 | board[i][j] |= 2; 15 | } 16 | } 17 | 18 | for(int i = 0;i < rows;i++) 19 | for(int j = 0;j < cols;j++) 20 | board[i][j] >>= 1; 21 | } 22 | }; -------------------------------------------------------------------------------- /289.Game of Life/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞具有一个初始状态 live(1)即为活细胞, 或 dead(0)即为死细胞。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律: 4 | 5 | 1. 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡; 6 | 2. 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活; 7 | 3. 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡; 8 | 4. 如果死细胞周围正好有三个活细胞,则该位置死细胞复活; 9 | 10 | 根据当前状态,写一个函数来计算面板上细胞的下一个(一次更新后的)状态 11 | 12 | ## 解答 13 | 14 | 如果直接在原矩阵上做0和1的变换,会影响后面的细胞的状态分析 15 | 16 | ### 方法一(需要一个额外的矩阵空间) 17 | 18 | 创建一个 m × n 的辅助空间,将下一个状态保存在辅助矩阵中,然后利用辅助矩阵更新原矩阵 19 | 20 | ### 方法二(原地修改) 21 | 22 | 如果要在原矩阵上修改,那么需要保留原来的状态,使得后面的分析不受影响,因此可以利用int右起第2位作为新的状态,当分析完所有细胞的新的状态后,再遍历一遍数组,每个元素右移一位得到新状态 -------------------------------------------------------------------------------- /29.Divide Two Integers/29.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int divide(int dividend, int divisor) { 4 | if(divisor == 0 || dividend == INT_MIN && divisor == -1) 5 | return INT_MAX; 6 | 7 | bool negative = !((dividend < 0 && divisor < 0) || (dividend > 0 && divisor > 0)); 8 | long long dvd = labs(dividend); 9 | long long dvs = labs(divisor); 10 | 11 | long long res = 0 ; 12 | while(dvd >= dvs){ 13 | long long tp = dvs; 14 | long long count = 1; 15 | while(dvd >= (tp << 1)){ 16 | count <<= 1; 17 | tp <<= 1; 18 | } 19 | res += count; 20 | dvd -= tp; 21 | } 22 | 23 | res = negative ? res * -1 : res; 24 | return res; 25 | } 26 | }; -------------------------------------------------------------------------------- /29.Divide Two Integers/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### 方法一 3 | 4 | 循环递减,每次减去除数,直到小于除数,记录次数 5 | 6 | 效率低,时间开销大 7 | 8 | ### 方法二 9 | 10 | 如果被除数比除数的2倍大,则将除数变为当前值的2倍(因此,次数也成倍增加),直到被除数小于除数的2倍。然后将被除数减去除数,处理剩下的值,例如被除数为15,除数为2,有下列过程: 11 | 12 | * 15大于2,因此初始化计数为1 13 | * 由于15大于4(2<<1),那么15里面肯定包含2个2,计数翻倍,变为2 14 | * 由于15大于8(4<<1),那么15里面肯定包含4个2,计数翻倍,变为4 15 | * 由于15小于16(8<<1),说明15不可能包含8个2,因此15减去8(4个2),变为7 16 | * 同样,对7进行上面的处理,新一轮计数为2(7包含2个2,不能包含4个2),因此总计数为6,将7减去4 17 | * 对3进行上面的处理,这一轮计数为1,因此总计数变为7,将3减去2 18 | * 对1进行上述处理,由于1小于2,所以停止 19 | * 因此,15里面包含7个2,即商为7 20 | 21 | 由于每次将除数翻倍,所以会比方法一快很多 -------------------------------------------------------------------------------- /295.Find Median from Data Stream/295.cpp: -------------------------------------------------------------------------------- 1 | class MedianFinder { 2 | public: 3 | /** initialize your data structure here. */ 4 | MedianFinder() : total(0) , small() , large() { 5 | } 6 | 7 | void addNum(int num) { 8 | if(total % 2 == 0){//total为偶数时,压入的是第奇数个元素 9 | if(!small.empty() && small.top() < num){ 10 | small.push(num); 11 | num = small.top(); 12 | small.pop(); 13 | } 14 | large.push(num); 15 | } 16 | else{ //total为奇数时,压入的是第偶数个元素 17 | if(!large.empty() && large.top() > num){ 18 | large.push(num); 19 | num = large.top(); 20 | large.pop(); 21 | } 22 | small.push(num); 23 | } 24 | total++; 25 | } 26 | 27 | double findMedian() { 28 | if(total == 0) return 0; 29 | if(total % 2 == 1){ 30 | return large.top(); 31 | } 32 | else 33 | return static_cast(large.top() + small.top()) / 2; 34 | } 35 | private: 36 | int total = 0; 37 | priority_queue,greater> small; //存放较大的一半元素 38 | priority_queue,less> large; //存放较小的一半元素 39 | }; 40 | 41 | /** 42 | * Your MedianFinder object will be instantiated and called as such: 43 | * MedianFinder obj = new MedianFinder(); 44 | * obj.addNum(num); 45 | * double param_2 = obj.findMedian(); 46 | */ -------------------------------------------------------------------------------- /297.Serialize and Deserialize Binary Tree/297.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Codec { 11 | public: 12 | 13 | // Encodes a tree to a single string. 14 | string serialize(TreeNode* root) { 15 | if (root == nullptr) return "#"; 16 | return to_string(root->val)+","+serialize(root->left)+","+serialize(root->right); 17 | } 18 | 19 | // Decodes your encoded data to tree. 20 | TreeNode* deserialize(string data) { 21 | return deserializeCore(data); 22 | } 23 | 24 | private: 25 | TreeNode* deserializeCore(string &data){ 26 | if(data == "") return NULL; 27 | 28 | if(data[0] == '#'){ 29 | data = data.substr(data.find(',') + 1); 30 | return NULL; 31 | } 32 | 33 | size_t idx; 34 | int val = stoi(data,&idx); 35 | data = data.substr(idx + 1); 36 | 37 | TreeNode *node = new TreeNode(val); 38 | 39 | node->left = deserializeCore(data); 40 | node->right = deserializeCore(data); 41 | 42 | return node; 43 | } 44 | }; 45 | 46 | // Your Codec object will be instantiated and called as such: 47 | // Codec codec; 48 | // codec.deserialize(codec.serialize(root)); -------------------------------------------------------------------------------- /3.Longest Substring Without Repeating Characters/3.cpp: -------------------------------------------------------------------------------- 1 | const int range = 256; 2 | 3 | class Solution { 4 | public: 5 | int lengthOfLongestSubstring(string s) { 6 | int state[range]; 7 | int globalmax = 0,localmax = 0; 8 | int beginidx = 0; 9 | 10 | for(int i = 0;i < range;i++) state[i] = -1; 11 | 12 | for(int idx = 0;idx < s.size();idx++){ 13 | if(state[s[idx]] < 0 || state[s[idx]] < beginidx){ 14 | localmax++; 15 | state[s[idx]] = idx; 16 | 17 | if(localmax > globalmax) globalmax = localmax; 18 | } 19 | else{ 20 | beginidx = state[s[idx]] + 1; 21 | localmax = idx - beginidx + 1; 22 | state[s[idx]] = idx; 23 | } 24 | } 25 | 26 | return globalmax; 27 | } 28 | }; -------------------------------------------------------------------------------- /3.Longest Substring Without Repeating Characters/README.md: -------------------------------------------------------------------------------- 1 | 分析字符串“abcabcbb”: 2 | 3 | * 第一个字符肯定不含重复,所以最长子串为“a”,长度为1,继续下一个字符 4 | * 字符b与a不重复,所以最长子串更新为“ab”,长度更新为2,继续下一个字符 5 | * 字符c与a,b都不重复,所以最长子串更新为“abc”,长度更新为3,继续下一个字符 6 | * 字符a与字符串"abc"中的字符a重复,所以如果存在一个包含当前字符a的子串,其长度大于“abc”,那么这个子串肯定不包含第一个字符a,所以去除第一个字符a,从子串“bca”继续分析 7 | * ... 8 | 9 | 上述步骤中隐含一定的规律: 10 | 11 | * 如果没有出现重复字符,这每次按1增加最长子串的长度 12 | * 如果出现重复字符,需要从原来最长子串中重复字符处截断,以截断位置后面的字符串为基础继续分析 13 | 14 | 使用一个数组作为hash_map记录字符最近一次出现的位置,没遍历到一个字符时,如果map中其位置为-1,表示这个字符之前未出现过,因此增加长度。如果出现过,并且这个字符出现在截断位置之前,那么说明这个字符并没有重复,因此也增加长度。如果出现过,但是在截断位置之后,说明发生重复,因此进行截断,并更新相应的变量 15 | -------------------------------------------------------------------------------- /300.Longest Increasing Subsequence/300.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int lengthOfLIS(vector& nums) { 4 | if (nums.size() == 0) 5 | return nums.size(); 6 | 7 | vector::iterator m = nums.begin(); // m will mark the virtual "S.end()". 8 | for (int& val : nums) { 9 | //lower_bound使用二分查找,查找[nums.begin(),m)区间内第一个大于等于val的元素 10 | //返回相应迭代器 11 | auto it = lower_bound(nums.begin(), m, val); 12 | *it = val; 13 | if (it == m) 14 | m++; 15 | } 16 | 17 | return m - nums.begin(); 18 | } 19 | }; -------------------------------------------------------------------------------- /31.Next Permutation/31.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void nextPermutation(vector& nums) { 4 | int sz = nums.size(); 5 | if(sz == 0) 6 | return; 7 | 8 | int i; 9 | for(i = sz - 2;i >= 0;i--){ 10 | if(nums[i] < nums[i + 1]){ 11 | int idx = i + 1;//右边降序序列中,需要与nums[i]交换的元素的下标 12 | for(int j = idx;j < sz;j++){ 13 | if(nums[j] > nums[i]) idx = j; 14 | else break; 15 | } 16 | 17 | int tp = nums[i]; 18 | nums[i] = nums[idx]; 19 | nums[idx] = tp; 20 | 21 | break; 22 | } 23 | } 24 | 25 | i++; 26 | int j = sz - 1; 27 | while(i < j){ 28 | nums[i] = nums[i] + nums[j]; 29 | nums[j] = nums[i] - nums[j]; 30 | nums[i] = nums[i] - nums[j]; 31 | i++; 32 | j--; 33 | } 34 | } 35 | }; -------------------------------------------------------------------------------- /31.Next Permutation/README.md: -------------------------------------------------------------------------------- 1 | 要找出数组所有序列中字典序比当前序列大的下一个序列,最差的方法是找出所有序列,分别与当前序列比较。时间复杂符是n! 2 | 3 | 考虑到要查找的序列只能比当前序列“稍微大一点”,因此应该调整数组右边部分的序列,如果右边部分为“降序”,则继续往左找,直到找到一个数,使得这个数和右边“降序”序列中的其中一个交换,可以得到一个更大的序列 4 | 5 | ``` 6 | [2,3] //当右边降序序列为[3]时,2小于3,所有交换2,3得到的序列[3,2]更大 7 | [1,3,2] //当右边降序序列为[3,2]时,1小于2,所以交换1,2得到的序列[2,3,1]更大 8 | ``` 9 | 10 | 但是在上面[1,3,2]的例子中,得到的[2,3,1]并不是最终结果,因为3,1是递减的,换成递增可以得到一个比当前序列更小,但仍比原始序列更大的序列,即[2,1,3],所以在交换后需要对右边序列进行一次排序。但是由于一开始我们是在右边序列中,找出比1大的最小的一个元素,也就是2,所以**交换后,右边序列仍然是降序的**,因此排序只需要反转右边的序列就行,需要O(n)的时间复杂度 11 | 12 | * **时间复杂度**:O(n) 13 | * **空间复杂度**:O(1) -------------------------------------------------------------------------------- /315.Count of Smaller Numbers After Self/315.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector countSmaller(vector& nums) { 4 | vector idx; 5 | for(int i = 0;i < nums.size();i++) idx.push_back(i); 6 | vector res(nums.size(),0); 7 | vector tmp(nums.size(),0); 8 | countSmallerCore(nums,idx,tmp,res,0,nums.size() - 1); 9 | return res; 10 | } 11 | private: 12 | void countSmallerCore(vector &nums,vector &idx,vector &tmp,vector &res,int l,int r){ 13 | if(l >= r) return; 14 | 15 | int mid = (l + r) >> 1; 16 | countSmallerCore(nums,idx,tmp,res,l,mid); 17 | countSmallerCore(nums,idx,tmp,res,mid + 1,r); 18 | merge(nums,idx,tmp,res,l,mid,mid + 1,r); 19 | } 20 | 21 | void merge(vector &nums,vector &idx,vector &tmp,vector &res,int l1,int r1,int l2,int r2){ 22 | int p1 = l1,p2 = l2,p = l1; 23 | while(p1 <= r1 && p2 <= r2){ 24 | if(nums[idx[p1]] > nums[idx[p2]]){ 25 | res[idx[p1]] += r2 - p2 + 1; 26 | tmp[p++] = idx[p1++]; 27 | } 28 | else 29 | tmp[p++] = idx[p2++]; 30 | } 31 | while(p1 <= r1) tmp[p++] = idx[p1++]; 32 | while(p2 <= r2) tmp[p++] = idx[p2++]; 33 | 34 | p = l1; 35 | while(p <= r2){ 36 | idx[p] = tmp[p]; 37 | p++; 38 | } 39 | } 40 | 41 | }; -------------------------------------------------------------------------------- /322.Coin Change/322.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int coinChange(vector& coins, int amount) { 4 | if(coins.empty() || amount == -1) return -1; 5 | 6 | vector state(amount + 1,-1); 7 | state[0] = 0; 8 | 9 | for(int price = 1;price <= amount;price++){ 10 | for(int i = 0;i < coins.size();i++) 11 | if(coins[i] <= price && state[price - coins[i]] != -1) 12 | if(state[price] == -1 || state[price] > state[price - coins[i]] + 1) 13 | state[price] = state[price - coins[i]] + 1; 14 | } 15 | 16 | return state[amount]; 17 | } 18 | }; -------------------------------------------------------------------------------- /322.Coin Change/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给出不同面额的金钱数组coins,元素为金钱的面额,每种面额的钱可以使用无数次。然后给出钱的总数amount,求最少需要找多少张钱 4 | 5 | ## 解答 6 | 7 | 动态规划 8 | 9 | 假设总共有n种面额的金钱,即coins数组的大小为n。然后假设这n种面额的钱中,有m张小于等于amount,那么可以从这m张里面选择1张作为找的钱,使问题规模更小,也就变成求总额为amount-coins[i]时,最少需要找多少张钱。总共衍生出m个更小的子问题。答案就是所有子问题中最小的一个(找钱张数最少的一个) -------------------------------------------------------------------------------- /324.Wiggle Sort II/324.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void wiggleSort(vector& nums) { 4 | //m为偶数下标的个数 5 | int n = nums.size(), m = (n + 1) >> 1; 6 | //lambda,将下标i进行映射 7 | auto mapping=[n](int i)->int{return (1 + 2 * i) % (n | 1);}; 8 | //获取中值 9 | auto miditr = nums.begin() + m - 1; 10 | nth_element(nums.begin(), miditr , nums.end()); 11 | int median = *miditr; 12 | 13 | //j: [0,1,2,3,...] (j > k时终止) 14 | //mapping[j]: [1,3,5,...,0,2,4,...] 15 | // 16 | //i: [0,1,2,3,...] 17 | //mapping[i]: [1,3,5,...,0,2,4,...] 18 | //k: [n-1,n-2,...] 19 | //mapping[k]: [...,4,2,0,...,5,3,1] 20 | for (int i = 0, j = 0, k = n - 1; j <= k;) { 21 | if (nums[mapping(j)] > median) //找到一个比中值大的数 22 | swap(nums[mapping(i++)], nums[mapping(j++)]); 23 | else if(nums[mapping(j)] < median) //找到一个比中值小的数,这里j不变 24 | swap(nums[mapping(j)], nums[mapping(k--)]); 25 | else //找到一个和中值相等的元素 26 | j++; 27 | } 28 | } 29 | }; -------------------------------------------------------------------------------- /326.Power of Three/326.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isPowerOfThree(int n) { 4 | // 1162261467 is 3^19, 3^20 is bigger than int 5 | return ( n>0 && 1162261467%n==0); 6 | } 7 | }; -------------------------------------------------------------------------------- /326.Power of Three/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个整数,写一个函数来判断它是否是 3 的幂次方。 4 | 5 | 示例 1: 6 | 7 | ``` 8 | 输入: 27 9 | 输出: true 10 | ``` 11 | 12 | 示例 2: 13 | 14 | ``` 15 | 输入: 0 16 | 输出: false 17 | ``` 18 | 19 | 示例 3: 20 | 21 | ``` 22 | 输入: 9 23 | 输出: true 24 | ``` 25 | 26 | 示例 4: 27 | 28 | ``` 29 | 输入: 45 30 | 输出: false 31 | ``` 32 | 33 | 进阶: 34 | 35 | 你能不使用循环或者递归来完成本题吗? 36 | 37 | ## 解答 38 | 39 | ### 方法一:递归 40 | 41 | ```c++ 42 | class Solution { 43 | public: 44 | bool isPowerOfThree(int n) { 45 | if(n <= 0) return false; 46 | if(n == 1) return true; 47 | if(n % 3 != 0) return false; 48 | return isPowerOfThree(n/3); 49 | } 50 | }; 51 | ``` 52 | 53 | ### 方法二:迭代 54 | 55 | ```c++ 56 | class Solution { 57 | public: 58 | bool isPowerOfThree(int n) { 59 | if(n < 0) return false; 60 | 61 | while(n){ 62 | if(n == 1) return true; 63 | if(n % 3 != 0) return false; 64 | n /= 3; 65 | } 66 | 67 | return false; 68 | } 69 | }; 70 | ``` 71 | 72 | ### 方法三:Discuss中不使用递归和迭代的方法 73 | 74 | ```c++ 75 | class Solution { 76 | public: 77 | bool isPowerOfThree(int n) { 78 | // 1162261467 is 3^19, 3^20 is bigger than int 79 | return ( n>0 && 1162261467%n==0); 80 | } 81 | }; 82 | 83 | //下列函数可以用以获取int中最大的3的幂的数 84 | int getMaxPowerOfThree() { 85 | int max = 1; 86 | while (max * 3 > max) max *= 3; 87 | return max; 88 | } 89 | ``` -------------------------------------------------------------------------------- /328.Odd Even Linked List/328.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* oddEvenList(ListNode* head) { 12 | if(!head) return head; 13 | 14 | ListNode *oddlist = head,*evenlist = head->next,*p1 = head,*p2 = NULL; 15 | int odd = 1; 16 | while(p1->next){ 17 | ListNode *tp = p1->next; 18 | p1->next = tp->next; 19 | p2 = p1; 20 | p1 = tp; 21 | odd = 1 - odd; 22 | } 23 | 24 | if(odd)//此时p1是奇数链表的尾节点 25 | p1->next = evenlist; 26 | else//此时p2是奇数链表的尾节点,因为odd不为1,说明上面while循环体至少被执行1次,所以p2不为NULL 27 | p2->next = evenlist; 28 | return oddlist; 29 | } 30 | }; -------------------------------------------------------------------------------- /328.Odd Even Linked List/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 将链表偶数位置的节点串成链表,移动到奇数位置节点组成的链表后 4 | 5 | ## 解答 6 | 7 | 使用两个指针oddlist和evenlist指向奇数链表和偶数链表的表头节点。然后使用一个指针p1遍历原链表,每次将一个节点指向它的下下个节点,从而将奇数链表和偶数链表拆开 8 | 9 | p1最后会执行原链表的最后一个结尾,这个节点可能是奇数链表的尾节点,也可能是偶数链表的尾节点。因此可以使用一个int变量odd做状态记录,通过odd判断p1是奇数链表的尾节点还是偶数链表的尾节点: 10 | 11 | * 如果是奇数链表的尾节点,那么将这个节点的下一个节点设为偶数链表的头结点,处理完成 12 | * 如果是偶数链表的尾节点,那么没有办法访问奇数链表的尾节点,因此使用另外一个指针p2,p2步伐p1慢,每次p1前移之前更新p2,因此在这种情况下p2指向奇数链表的尾节点,将其下一个节点设为偶数链表的头结点来完成处理 13 | -------------------------------------------------------------------------------- /33.Search in Rotated Sorted Array/33.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int search(vector& nums, int target) { 4 | if(nums.size() == 0) 5 | return -1; 6 | 7 | int begin = 0 , end = nums.size() - 1; 8 | int mid; 9 | while(begin <= end){ 10 | mid = (begin + end) / 2; 11 | if(nums[mid] > nums[end]){//mid在左边 12 | if(nums[mid] == target) return mid; 13 | else if(nums[mid] < target || target <= nums[end]) begin = mid + 1; 14 | else end = mid - 1; 15 | } 16 | else{//mid在右边 17 | if(nums[mid] == target) return mid; 18 | else if(nums[mid] < target && target <= nums[end]) begin = mid + 1; 19 | else end = mid - 1; 20 | } 21 | } 22 | return -1; 23 | } 24 | }; -------------------------------------------------------------------------------- /33.Search in Rotated Sorted Array/README.md: -------------------------------------------------------------------------------- 1 | 根据mid位置的值判断mid是在左半部分还是右半部分 2 | 3 | * 如果在左半部分(说明mid位置的值比end位置的值大) 4 | * 当target大于mid位置的值或target小于等于end位置的值时,继续在右边查找 5 | * 否则,在左边查找 6 | + 如果在右半部分(说明mid位置的值比end位置的值小) 7 | * 当target大于mid位置的值并且target小于end位置的值时,才能在右边查找 8 | * 否则,在左边查找 -------------------------------------------------------------------------------- /334.Increasing Triplet Subsequence/334.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool increasingTriplet(vector& nums) { 4 | if(nums.size() < 3) return false; 5 | 6 | int min = INT_MAX,max = INT_MAX; 7 | for(int e : nums){ 8 | if(e <= min) min = e; 9 | else if(e <= max) max = e; 10 | else return true; 11 | } 12 | 13 | return false; 14 | } 15 | }; -------------------------------------------------------------------------------- /334.Increasing Triplet Subsequence/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 判断整形数组中是否存在三元升序子序列 4 | 5 | > 这个题和[最长升序子序列](https://leetcode.com/problems/longest-increasing-subsequence/description/)一样,都是整形数组中的升序子序列的问题。可以扩展为判断整形数组中是否存在n元升序子序列 6 | 7 | ## 解答 8 | 9 | 维护一个二元升序子序列,即使用一个变量small,和一个变量big。遍历数组: 10 | 11 | * 如果一个数小于或等于small,则更新small 12 | * 如果大于small,但是小于等于big,则更新big 13 | * 如果大于big,那么就找到一个三元升序子序列 14 | 15 | 这个地方可能不太好理解的是:如果在更新完small后,出现了一个大于big的数,那么判断为找到了一个三元升序子序列。这种情况下,big的最后一次更新在small前,small,big和最后大于big的这个数的位置顺序是:big,small,大于big的数。这个顺序不是一个三元升序序列,但是我们判断结果是找到了三元升序子序列,这个解决是对的,但是上面这3个数并不是正确的升序序列 16 | 17 | 几个例子,假设初始数组如下: 18 | 19 | ``` 20 | 2,3,1,4 21 | ``` 22 | 23 | 处理到3时: 24 | 25 | ``` 26 | small = 2 27 | big = 3 28 | ``` 29 | 30 | 处理1。因为1小于small,所以更新small: 31 | 32 | ``` 33 | small = 1 34 | big = 3 35 | ``` 36 | 37 | 处理4。因为4大于big,所以判断为找到了三元升序子序列 38 | 39 | 此时3个数为1,3,4,但是在数组中对应的顺序是3,1,4。那为什么结果是对的?因为我们判断为true的条件是是:找到一个大于big的数。因为当找到一个大于small的数时,才会更新big,虽然这里最后更新了small,但是在最后一次更新big之前,肯定更新过small,所以数组中确实是存在升序的三元子序列。也就是说,真正的三元升序子序列是2,3,4 -------------------------------------------------------------------------------- /34.Search for a Range/34.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector searchRange(vector& nums, int target) { 4 | int l = searchRangel(nums,target); 5 | int r = searchRanger(nums,target); 6 | 7 | vector v; 8 | v.push_back(l); 9 | v.push_back(r); 10 | return v; 11 | } 12 | 13 | int searchRangel(const vector &nums,int target) 14 | { 15 | int l = 0,r = nums.size() - 1; 16 | int mid; 17 | 18 | while(l <= r){ 19 | mid = (l + r) / 2; 20 | if(nums[mid] == target){ 21 | if(mid == 0 || nums[mid - 1] != nums[mid]) return mid; 22 | else r = mid - 1; 23 | } 24 | else if(nums[mid] > target) r = mid - 1; 25 | else l = mid + 1; 26 | } 27 | 28 | return -1; 29 | } 30 | 31 | int searchRanger(const vector &nums,int target) 32 | { 33 | int l = 0,r = nums.size() - 1; 34 | int mid,end = r; 35 | 36 | while(l <= r){ 37 | mid = (l + r) / 2; 38 | if(nums[mid] == target){ 39 | if(mid == end || nums[mid + 1] != nums[mid]) return mid; 40 | else l = mid + 1; 41 | } 42 | else if(nums[mid] > target) r = mid - 1; 43 | else l = mid + 1; 44 | } 45 | 46 | return -1; 47 | } 48 | }; -------------------------------------------------------------------------------- /34.Search for a Range/README.md: -------------------------------------------------------------------------------- 1 | 使用二分查找,分别找到数字的下边界和上边界 2 | 3 | > 两个二分查找不需要额外定义2个函数,可以在一个函数内完成 -------------------------------------------------------------------------------- /341.Flatten Nested List Iterator/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给出一个嵌套的整数列表,实现一个扁平化遍历该链表的迭代器 4 | 5 | 例如: 6 | 7 | 给定列表 ```[[1,1],2,[1,1]]```, 8 | 9 | 通过重复调用 next 直到 hasNext 返回false,next 返回的元素的顺序应该是: ```[1,1,2,1,1]``` 10 | 11 | ## 解答 12 | 13 |
14 | 15 | 上图给出了一个扁平化处理过程,从处理过程上看,当遇到一个嵌套list时,会进入嵌套的list处理该list,当嵌套list处理完成后,会返回外层list继续处理。这个过程是一个递归的处理过程,因此可以使用两个栈,一个栈begin保存每层list的当前迭代器,另一个栈end保存每层list的尾后迭代器,用于判断何时一层list处理结束。begin.top()和end.top()是同一层list的当前迭代器和尾后迭代器 -------------------------------------------------------------------------------- /344.Reverse String/344.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string reverseString(string s) { 4 | int l = 0,r = s.length() - 1; 5 | while(l < r) 6 | swap(s[l++],s[r--]); 7 | return s; 8 | } 9 | }; -------------------------------------------------------------------------------- /347.Top K Frequent Elements/347.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector topKFrequent(vector& nums, int k) { 4 | //统计每个元素出现的次数 5 | unordered_map map; 6 | for(int num : nums) 7 | map[num]++; 8 | 9 | //桶的下标表示元素出现的次数,所以下标越大出现越频繁 10 | vector> bucket(nums.size() + 1); 11 | for(auto p : map) 12 | bucket[p.second].push_back(p.first); 13 | 14 | vector res; 15 | //从后面的桶往前面遍历 16 | for(int i = bucket.size() - 1;i >= 0 && res.size() < k;--i){ 17 | //遍历桶中的每个数 18 | for(int num : bucket[i]){ 19 | res.push_back(num); 20 | if(res.size() == k) 21 | break; 22 | } 23 | } 24 | 25 | return res; 26 | } 27 | }; -------------------------------------------------------------------------------- /347.Top K Frequent Elements/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 4 | 5 | 例如, 6 | 7 | 给定数组 ```[1,1,1,2,2,3]``` , 和 ```k = 2```,返回 ```[1,2]```。 8 | 9 | 注意: 10 | 11 | * 假设给定的 k 总是合理的,1 ≤ k ≤ 数组中不相同的元素的个数。 12 | * 算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。 13 | 14 | ## 解答 15 | 16 | 首先统计每个元素的频率,即出现次数 17 | 18 | 然后创建桶数组,下标表示元素的频率,每个桶也是一个数组,内含出现频率为相应值的元素。例如bucket[i]表示出现频率为i的桶,内含所有出现i次的元素 19 | 20 | 按频率”从高到低“输出k个数字 -------------------------------------------------------------------------------- /350.Intersection of Two Arrays II/350.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector intersect(vector& nums1, vector& nums2) { 4 | unordered_map countMap; 5 | 6 | vector res; 7 | for(int num : nums1) countMap[num]++; 8 | 9 | for(int num : nums2) 10 | if(countMap[num]-- > 0) 11 | res.push_back(num); 12 | 13 | return res; 14 | } 15 | }; -------------------------------------------------------------------------------- /350.Intersection of Two Arrays II/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定两个数组,写一个方法来计算它们的交集。 4 | 5 | 例如: 6 | 7 | 8 | 给定 `nums1 = [1, 2, 2, 1]`, `nums2 = [2, 2]`, 返回 `[2, 2]`. 9 | 10 | 注意: 11 | 12 | * 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。 13 | * 我们可以不考虑输出结果的顺序。 14 | 15 | 跟进: 16 | 17 | * 如果给定的数组已经排好序呢?你将如何优化你的算法?(**归并处理**) 18 | * 如果 nums1 的大小比 nums2 小很多,哪种方法更优? 19 | * 如果nums2的元素存储在磁盘上,内存是有限的,你不能一次加载所有的元素到内存中,你该怎么办?(**哈希成多个小文件,小文件分治求交集**) 20 | 21 | ## 解答 22 | 23 | 使用一个hash表统计一个数组中每个数字出现的次数,然后遍历另外一个数组,如果某个数组出现在哈希表中则添加到结果中,由于可以包含重复数字,所以需要计数每个数字出现的次数: 24 | 25 | ```c++ 26 | class Solution { 27 | public: 28 | vector intersect(vector& nums1, vector& nums2) { 29 | unordered_map countMap; 30 | 31 | vector res; 32 | for(int num : nums1) countMap[num]++; 33 | 34 | for(int num : nums2) 35 | if(countMap[num]-- > 0) 36 | res.push_back(num); 37 | 38 | return res; 39 | } 40 | }; 41 | ``` -------------------------------------------------------------------------------- /36.Valid Sudoku/README.md: -------------------------------------------------------------------------------- 1 | 按照数独的要求: 2 | 3 | 1. 每行不能包含相同的数字 4 | 2. 每列不能包含相同的数字 5 | 3. 9个3\*3的子格不能包含相同的数字 6 | 7 | 因此,可以分别对3个条件进行检测,如果都满足,那么返回true,否则返回false 8 | 9 | 那么问题是,怎么判断一行,一列,或者一个3\*3的子格是否不包含重复的数字? 10 | 11 | 由于数字范围是0~9,因此可以创建一个数组nums,记录每个数字是否出现,如果出现1,则将nums[1]设为1,某个数已经出现过,即nums[i]!=0,说明数字重复出现,因此返回false -------------------------------------------------------------------------------- /371.Sum of Two Integers/371.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int getSum(int a, int b) { 4 | int tp = (a & b) << 1; 5 | a = a ^ b,b = tp; 6 | while(b){ 7 | tp = (a & b) << 1; 8 | a = a ^ b; 9 | b = tp; 10 | } 11 | return a; 12 | } 13 | }; -------------------------------------------------------------------------------- /371.Sum of Two Integers/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 不使用运算符 + 和-,计算两整数a 、b之和。 4 | 5 | 示例: 6 | 7 | 若 a = 1 ,b = 2,返回 3。 8 | 9 | ## 解答 10 | 11 | 两个数异或(^)可以得到两数二进制对应位为0和1相加的结果,但是所有1和1会得到0,因此再对两数做与(&)操作然后左移1位(<<),即是得到所有的进位。因此得到两个新的数,对这两个新的数重复上述步骤直到没有进位 12 | 13 | ```c++ 14 | class Solution { 15 | public: 16 | int getSum(int a, int b) { 17 | int tp = (a & b) << 1; 18 | a = a ^ b,b = tp; 19 | while(b){ 20 | tp = (a & b) << 1; 21 | a = a ^ b; 22 | b = tp; 23 | } 24 | return a; 25 | } 26 | }; 27 | ``` -------------------------------------------------------------------------------- /378.Kth Smallest Element in a Sorted Matrix/378.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | struct compare{ 4 | bool operator()(const pair> &p1,const pair> &p2){ 5 | return p1.first > p2.first; 6 | } 7 | }; 8 | int kthSmallest(vector>& matrix, int k) { 9 | //template , class Compare = less > 10 | priority_queue>,vector>>,compare> pq; 11 | 12 | for(int i = 0;i < matrix.size();i++) 13 | pq.push(make_pair(matrix[i][0],make_pair(i,0))); 14 | 15 | int res,cols = matrix[0].size(); 16 | while(k--){ 17 | res = pq.top().first; 18 | int i = pq.top().second.first,j = pq.top().second.second; 19 | pq.pop(); 20 | if(j < cols - 1) 21 | pq.push(make_pair(matrix[i][j + 1],make_pair(i,j+1))); 22 | } 23 | 24 | return res; 25 | } 26 | }; -------------------------------------------------------------------------------- /38.Count and Say/38.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string countAndSay(int n) { 4 | if(n <= 0) return ""; 5 | else if(n == 1) return "1"; 6 | 7 | string res = "1"; 8 | while(--n){ 9 | string s = ""; 10 | char c = res[0]; 11 | int count = 1; 12 | for(int i = 1;i < res.length();i++){ 13 | if(res[i] == c) count++; 14 | else{ 15 | s += to_string(count) + c; 16 | c = res[i]; 17 | count = 1; 18 | } 19 | } 20 | s += to_string(count) + c; 21 | res = s; 22 | } 23 | 24 | return res; 25 | } 26 | }; -------------------------------------------------------------------------------- /38.Count and Say/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 报数序列是指一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下: 4 | 5 | ``` 6 | 1. 1 7 | 2. 11 8 | 3. 21 9 | 4. 1211 10 | 5. 111221 11 | 12 | 1 被读作 "one 1" ("一个一") , 即 11 13 | 11 被读作 "two 1s" ("两个一"), 即 21 14 | 21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211 15 | ``` 16 | 17 | 给定一个正整数 n ,输出报数序列的第 n 项。 18 | 19 | 注意:整数顺序将表示为一个字符串。 20 | 21 | 示例 1: 22 | 23 | ``` 24 | 输入: 1 25 | 输出: "1" 26 | ``` 27 | 28 | 示例 2: 29 | 30 | ``` 31 | 输入: 4 32 | 输出: "1211" 33 | ``` 34 | 35 | ## 解答 36 | 37 | 统计每个数字出现的次数,在下一个不同数字出现时,将这个数字的结果添加到结果字符串中,然后统计下一个数字 38 | 39 | ```c++ 40 | class Solution { 41 | public: 42 | string countAndSay(int n) { 43 | if(n <= 0) return ""; 44 | else if(n == 1) return "1"; 45 | 46 | string res = "1"; 47 | while(--n){ 48 | string s = ""; 49 | char c = s[0]; 50 | int count = 1; 51 | for(int i = 1;i < s.length();i++){ 52 | if(s[i] == c) 53 | count++; 54 | else{ 55 | s += to_string(count); 56 | c = s[i]; 57 | count = 1; 58 | } 59 | } 60 | res = s; 61 | } 62 | 63 | return res; 64 | } 65 | }; 66 | ``` -------------------------------------------------------------------------------- /380.Insert Delete GetRandom O(1)/380.cpp: -------------------------------------------------------------------------------- 1 | class RandomizedSet { 2 | public: 3 | /** Initialize your data structure here. */ 4 | RandomizedSet() { 5 | //srand(time(0)); 6 | } 7 | 8 | /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ 9 | bool insert(int val) { 10 | if(map.find(val) != map.end()) return false; 11 | nums.emplace_back(val); 12 | map[val] = nums.size() - 1; 13 | return true; 14 | } 15 | 16 | /** Removes a value from the set. Returns true if the set contained the specified element. */ 17 | bool remove(int val) { 18 | if(map.find(val) == map.end()) return false; 19 | int idxOfval = map[val]; 20 | int last = nums.back(); 21 | nums[idxOfval] = last; 22 | map[last] = idxOfval; 23 | map.erase(val); 24 | nums.pop_back(); 25 | return true; 26 | } 27 | 28 | /** Get a random element from the set. */ 29 | int getRandom() { 30 | return nums[rand() % nums.size()]; 31 | } 32 | private: 33 | vector nums; //存储元素 34 | unordered_map map; //存储元素在nums中的下标 35 | }; 36 | 37 | /** 38 | * Your RandomizedSet object will be instantiated and called as such: 39 | * RandomizedSet obj = new RandomizedSet(); 40 | * bool param_1 = obj.insert(val); 41 | * bool param_2 = obj.remove(val); 42 | * int param_3 = obj.getRandom(); 43 | */ -------------------------------------------------------------------------------- /384.Shuffle an Array/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 打乱一个没有重复元素的数组 4 | 5 | 示例: 6 | 7 | ```c++ 8 | // 以数字集合 1, 2 和 3 初始化数组。 9 | int[] nums = {1,2,3}; 10 | Solution solution = new Solution(nums); 11 | 12 | // 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。 13 | solution.shuffle(); 14 | 15 | // 重设数组到它的初始状态[1,2,3]。 16 | solution.reset(); 17 | 18 | // 随机返回数组[1,2,3]打乱后的结果。 19 | solution.shuffle(); 20 | ``` 21 | 22 | ## 解答 23 | 24 | 使用[Fisher–Yates shuffle洗牌算法](https://www.youtube.com/watch?v=tLxBwSL3lPQ) 25 | 26 | Fisher–Yates shuffle洗牌算法的思想是,每次从未处理的牌中随机选择一个,与未处理牌中最后一张牌交换,从而打乱顺序。算法本身没有保证在取每个随机数的时候是等概率的,它保证的是可以等概率的生成给定数组的任一排列。对于n张牌的数组,处理过程如下: 27 | 28 | * 第一次:从[0,n-1]中,随机选择一个位置k1,交换位置k1和位置n-1的元素 29 | * 第二次:从[0,n-2]中,随机选择一个位置k2,交换位置k2和位置n-2的元素 30 | * ... -------------------------------------------------------------------------------- /387.First Unique Character in a String/387.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int firstUniqChar(string s) { 4 | vector idxArray(26,-1); 5 | for(int i = 0;i < s.length();i++){ 6 | if(idxArray[s[i] - 'a'] == -1) idxArray[s[i] - 'a'] = i; 7 | else idxArray[s[i] - 'a'] = -2; 8 | } 9 | 10 | int minIdx = -1; 11 | for(int idx : idxArray) 12 | if(idx != -1 && idx != -2){ 13 | if(minIdx == -1) minIdx = idx; 14 | else if(idx < minIdx) minIdx = idx; 15 | } 16 | 17 | return minIdx; 18 | } 19 | }; -------------------------------------------------------------------------------- /387.First Unique Character in a String/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 4 | 5 | 案例: 6 | 7 | ``` 8 | s = "leetcode" 9 | 返回 0. 10 | 11 | s = "loveleetcode", 12 | 返回 2. 13 | ``` 14 | 15 | 注意事项:您可以假定该字符串只包含小写字母。 16 | 17 | ## 解答 18 | 19 | 题目可以假定字符串只包含小写字母,因此使用26个元素的数组,分别表示字母'a'-'z'出现的位置,因为出现的位置大于等于0,因此,用-1表示字母并未在字符串中出现,-2表示出现多次,那么最后遍历这个数组,不等于-1和-2的最小值就是第一个唯一字符出现的位置 20 | 21 | ```c++ 22 | class Solution { 23 | public: 24 | int firstUniqChar(string s) { 25 | vector idxArray(26,-1); 26 | for(int i = 0;i < s.length();i++){ 27 | if(idxArray[s[i] - 'a'] == -1) idxArray[s[i] - 'a'] = i; 28 | else idxArray[s[i] - 'a'] = -2; 29 | } 30 | 31 | int minIdx = -1; 32 | for(int idx : idxArray) 33 | if(idx != -1 && idx != -2){ 34 | if(minIdx == -1) minIdx = idx; 35 | else if(idx < minIdx) minIdx = idx; 36 | } 37 | 38 | return minIdx; 39 | } 40 | }; 41 | ``` -------------------------------------------------------------------------------- /39.Combination Sum/39.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> combinationSum(vector& candidates, int target) { 4 | if(candidates.size() == 0) return vector>(); 5 | 6 | std::sort(candidates.begin(),candidates.end()); 7 | vector> res; 8 | vector set; 9 | combinationSum(candidates,target,0,res,set); 10 | 11 | return res; 12 | } 13 | private: 14 | void combinationSum(const vector &candidates,int target,int idx,vector> &res,vector &set){ 15 | if(idx == candidates.size()){ 16 | if(!target) res.push_back(set); 17 | return; 18 | } 19 | 20 | if(target >= candidates[idx]){ 21 | combinationSum(candidates,target,idx + 1,res,set); 22 | set.push_back(candidates[idx]); 23 | combinationSum(candidates,target - candidates[idx],idx,res,set); 24 | set.pop_back(); 25 | } 26 | } 27 | }; -------------------------------------------------------------------------------- /39.Combination Sum/README.md: -------------------------------------------------------------------------------- 1 | 对于每个数字,可以选择要或者不要,使用一个数组set来保存选择要的数字 2 | 3 | 在做下一次选择时,可能有两种情况: 4 | 5 | 1. set中的数字和已经等于target,此时将set存入结果中 6 | 2. 如果1不成立,并且到达结尾,此时不存储set,直接返回 7 | 8 | 由于允许重复使用一个数字,如果选择使用这个数字,因为可能会重复选择,所以继续在当前位置处理。如果不选择使用这个数字,则继续处理下一个数字 9 | 10 | 可以先对数组进行排序,如果加上当前数字的总和已经超过target,则停止这个路径的处理。通过剪枝,去掉不可能的子集 11 | 12 | -------------------------------------------------------------------------------- /395.Longest Substring with At Least K Repeating Characters/395.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int longestSubstring(string s, int k) { 4 | vector cases(26,0); 5 | for(char c : s) cases[c - 'a']++; 6 | 7 | int len = s.length(); 8 | int idx = 0; 9 | while(idx < len && cases[s[idx] - 'a'] >= k) {idx++;} 10 | if(idx == len) return len; 11 | 12 | int left = longestSubstring(s.substr(0,idx),k); 13 | //这里是个优化:跳过所有相连的、出现次数少于k次的字符 14 | while(idx < len && cases[s[idx] - 'a'] < k) {idx++;} 15 | int right = longestSubstring(s.substr(idx),k); 16 | 17 | return max(left,right); 18 | } 19 | }; -------------------------------------------------------------------------------- /395.Longest Substring with At Least K Repeating Characters/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度 4 | 5 | 示例 1: 6 | 7 | ``` 8 | 输入: 9 | s = "aaabb", k = 3 10 | 11 | 输出: 12 | 3 13 | 14 | 最长子串为 "aaa" ,其中 'a' 重复了 3 次 15 | ``` 16 | 17 | 示例 2: 18 | 19 | ``` 20 | 输入: 21 | s = "ababbc", k = 2 22 | 23 | 输出: 24 | 5 25 | 26 | 最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次 27 | ``` 28 | 29 | ## 解答 30 | 31 | 1. 遍历字符串,统计每个字符出现的次数 32 | 2. 找到字符串中第一个出现次数少于K的字符,这个字符显然不会出现在满足要求的子串中,因此它将字符串分割成2个子串 33 | 3. 递归处理,最长子串必定出现在左边或者右边 34 | 35 | ```c++ 36 | class Solution { 37 | public: 38 | int longestSubstring(string s, int k) { 39 | vector cases(26,0); 40 | for(char c : s) cases[c - 'a']++; 41 | 42 | int len = s.length(); 43 | int idx = 0; 44 | while(idx < len && cases[s[idx] - 'a'] >= k) {idx++;} 45 | if(idx == len) return len; 46 | 47 | int left = longestSubstring(s.substr(0,idx),k); 48 | //这里是个优化:跳过所有相连的、出现次数少于k次的字符 49 | while(idx < len && cases[s[idx] - 'a'] < k) {idx++;} 50 | int right = longestSubstring(s.substr(idx),k); 51 | 52 | return max(left,right); 53 | } 54 | }; 55 | ``` 56 | 57 | 由于题目给出了字符串只包含小写字母,所有map直接使用了vector。如果没有限定字符串的字符范围,可以使用unordered_map 58 | -------------------------------------------------------------------------------- /4.Median of Two Sorted Arrays/4.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 4 | if(nums2.size() < nums1.size()) 5 | return findMedianSortedArrays(nums2,nums1); 6 | 7 | int sz = nums1.size() + nums2.size(); 8 | int sz1l = 0,sz1r = nums1.size(); 9 | int sz1 = 0,sz2 = 0; 10 | while(sz1 <= nums1.size()){ 11 | sz1 = (sz1l + sz1r) / 2; 12 | sz2 = sz / 2 - sz1; 13 | int l1 = sz1 == 0 ? INT_MIN : nums1[sz1 - 1]; 14 | int r1 = sz1 == nums1.size() ? INT_MAX : nums1[sz1]; 15 | int l2 = sz2 == 0 ? INT_MIN : nums2[sz2 - 1]; 16 | int r2 = sz2 == nums2.size() ? INT_MAX : nums2[sz2]; 17 | if(l1 > r2) 18 | sz1r = sz1 - 1; 19 | else if(l2 > r1) 20 | sz1l = sz1 + 1; 21 | else{ 22 | if(sz % 2 == 0){ 23 | l1 = l1 > l2 ? l1 : l2; 24 | r1 = r1 < r2 ? r1 : r2; 25 | return (double)(l1 + r1) / 2; 26 | } 27 | else{ 28 | r1 = r1 < r2 ? r1 : r2; 29 | return r1; 30 | } 31 | } 32 | 33 | } 34 | 35 | return -1; 36 | } 37 | }; -------------------------------------------------------------------------------- /40.Combination Sum II/40.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> combinationSum2(vector& candidates, int target) { 4 | vector> res; 5 | vector set; 6 | 7 | sort(candidates.begin(),candidates.end()); 8 | 9 | combinationSum2(candidates,target,res,set,0); 10 | 11 | return res; 12 | } 13 | 14 | private: 15 | void combinationSum2(vector &candidates,int target,vector> &res,vector &set,int idx){ 16 | if(target == 0){ 17 | res.push_back(set); 18 | return; 19 | } 20 | 21 | for(int i = idx;i < candidates.size() && target >= candidates[i];++i){ 22 | //if(i != idx && candidates[i] == candidates[i - 1]) continue; 23 | if(i == idx || candidates[i] != candidates[i - 1]){ 24 | set.push_back(candidates[i]); 25 | combinationSum2(candidates,target - candidates[i],res,set,i + 1); 26 | set.pop_back(); 27 | } 28 | } 29 | } 30 | }; -------------------------------------------------------------------------------- /40.Combination Sum II/README.md: -------------------------------------------------------------------------------- 1 | > 和上一题不同,这一题中,候选数组中可能包含相同的元素 2 | 3 | 对于一个数字,同样是使用或不使用两种选择,考虑候选数组[10,1,2,7,6,1,5],排序后,数组为[1,1,2,5,6,7,10],如果只通过递归来处理每个数使用或不使用这两种情况,那么当: 4 | 5 | * 第一个1使用,第二个1不使用 6 | * 第一个1不使用,第二个1使用 7 | 8 | 这两种情况就会产生冗余 9 | 10 | 因此,这里不能单纯的只使用递归来实现,需要结合迭代: 11 | 12 | * **迭代**:从头到尾遍历候选数组的中的每个元素,对于位置i的元素,有2个种可能: 13 | 1. 位置i的元素和位置i-1的元素相等。此时直接跳过位置i的元素,否则会与前一次处理产生冗余 14 | 2. 位置i的元素和位置i-1的元素不相等,此时需要处理位置i的元素 15 | * **递归**:对于迭代过程中需要处理的元素,假设使用这个元素,然后递归,对后续子候选数组进行相同的处理 16 | 17 | 在迭代中,当遍历至位置i时,表示位置i之前的元素都不使用。因为在遍历i之前的元素时,已经处理了所有包含这些元素的子数组了,因此不需要再重复考虑相同的情况 18 | 19 | 20 | -------------------------------------------------------------------------------- /41.First Missing Positive/41.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int firstMissingPositive(vector& nums) { 4 | int n = nums.size(); 5 | for(int i = 0;i < n;i++){ 6 | while(nums[i] > 0 && nums[i] <= n && nums[i] != (i+1) && nums[nums[i] - 1] != nums[i]){ 7 | int tp = nums[nums[i] - 1]; 8 | nums[nums[i] - 1] = nums[i]; 9 | nums[i] = tp; 10 | } 11 | } 12 | 13 | for(int i = 0;i < n;i++){ 14 | if(nums[i] != i + 1) return i + 1; 15 | } 16 | 17 | return n + 1; 18 | } 19 | }; -------------------------------------------------------------------------------- /41.First Missing Positive/README.md: -------------------------------------------------------------------------------- 1 | 假设对于大小为n(n>0)的数组,这n个数可以分为以下几种情况: 2 | 3 | 1. n个数都小于等于0 4 | 2. n个数都大于n 5 | 3. 存在一个或多个位于[1,n]的数 6 | 7 | 对于情况1,要查找的第一个缺失的正数就是1;对于情况2,要查找的第一个缺失的正数也是1;问题是对于情况3应该怎么考虑 8 | 9 | 假设这些位于[1,n]的数i,在数组中的位置为i-1,而小于等于0的数,以及大于n的数,在数组剩余位置: 10 | 11 | * 如果数组所有的数都在[1,n],那么每个元素都在其值减1的位置,此时要找的第一个缺失的整数就是n+1 12 | * 否则,**数组中,必然存在一个位置idx,其元素值不等于idx+1**,而范围[1,n]就是正数序列最开始的n个数,因此,从左往右查找第一个下标加1不等于值的位置,那么要找的第一个缺失的正数就是该位置的下标加1 13 | 14 | 剩下的就是将范围在[1,n]的元素放置到正确的位置了。 15 | 16 | > **使数组大小为n,刚好可以放下前n个正数,由于0不是正数,那么将数组下标i的槽存放正数i+1。经过这样的处理后,第一个不满足上述关系的槽应该存放的那个正数,就是第一个缺失的正数** -------------------------------------------------------------------------------- /412.Fizz Buzz/412.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector fizzBuzz(int n) { 4 | vector res; 5 | for(int i = 1;i <= n;i++){ 6 | if(i % 15 == 0) res.push_back("FizzBuzz"); 7 | else if(i % 5 == 0) res.push_back("Buzz"); 8 | else if(i % 3 == 0) res.push_back("Fizz"); 9 | else res.push_back(to_string(i)); 10 | } 11 | return res; 12 | } 13 | }; -------------------------------------------------------------------------------- /412.Fizz Buzz/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 写一个程序,输出从 1 到 n 数字的字符串表示。 4 | 5 | 1. 如果 n 是3的倍数,输出“Fizz”; 6 | 2. 如果 n 是5的倍数,输出“Buzz”; 7 | 3. 如果 n 同时是3和5的倍数,输出 “FizzBuzz”。 8 | 9 | 示例: 10 | 11 | ``` 12 | n = 15, 13 | 14 | 返回: 15 | [ 16 | "1", 17 | "2", 18 | "Fizz", 19 | "4", 20 | "Buzz", 21 | "Fizz", 22 | "7", 23 | "8", 24 | "Fizz", 25 | "Buzz", 26 | "11", 27 | "Fizz", 28 | "13", 29 | "14", 30 | "FizzBuzz" 31 | ] 32 | ``` 33 | 34 | ## 解答 35 | 36 | ```c++ 37 | class Solution { 38 | public: 39 | vector fizzBuzz(int n) { 40 | vector res; 41 | for(int i = 1;i <= n;i++){ 42 | if(i % 15 == 0) res.push_back("FizzBuzz"); 43 | else if(i % 5 == 0) res.push_back("Buzz"); 44 | else if(i % 3 == 0) res.push_back("Fizz"); 45 | else res.push_back(to_string(i)); 46 | } 47 | return res; 48 | } 49 | }; 50 | ``` -------------------------------------------------------------------------------- /42.Trapping Rain Water/42.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int trap(vector& height) { 4 | int water = 0,sz = height.size(); 5 | int left_bar = 0,right_bar = sz - 1; 6 | int max_left = 0,max_right = 0; 7 | 8 | while(left_bar < right_bar){ 9 | if(height[left_bar] < height[right_bar]){ 10 | if(height[left_bar] < max_left) water += max_left - height[left_bar]; 11 | else max_left = height[left_bar]; 12 | left_bar++; 13 | } 14 | else{ 15 | if(height[right_bar] < max_right) water += max_right - height[right_bar]; 16 | else max_right = height[right_bar]; 17 | right_bar--; 18 | } 19 | } 20 | 21 | return water; 22 | } 23 | }; -------------------------------------------------------------------------------- /44.Wildcard Matching/44.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isMatch(string s, string p) { 4 | int len1 = s.length(),len2 = p.length(); 5 | 6 | vector> matches(len1 + 1,vector(len2 + 1)); 7 | for(int i = 0;i < len1;i++) // p == "" 8 | matches[i][len2] = 0; 9 | matches[len1][len2] = 1; // p == "" && s == "" 10 | for(int j = len2 - 1;j >= 0;j--) // s == "" 11 | matches[len1][j] = (p[j] == '*' && matches[len1][j + 1]); 12 | 13 | for(int i = len1 - 1;i >= 0;i--){ // s.substr[i] match p.substr[j] ? 14 | for(int j = len2 - 1;j >= 0;j--){ 15 | if(p[j] == '?') 16 | matches[i][j] = matches[i + 1][j + 1]; 17 | else if(p[j] == '*') 18 | matches[i][j] = matches[i + 1][j] || matches[i][j + 1]; 19 | else 20 | matches[i][j] = (s[i] == p[j] && matches[i + 1][j + 1]); 21 | } 22 | } 23 | 24 | return matches[0][0]; 25 | } 26 | }; -------------------------------------------------------------------------------- /45.Jump Game II/45.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int jump(vector& nums) { 4 | if(nums.size() == 1) return 0; 5 | 6 | int target = nums.size() - 1,res = 0; 7 | deque d; 8 | d.push_back(0); 9 | vector flags(nums.size(),0); //防止重复添加节点 10 | flags[0] = 1; 11 | 12 | while(!d.empty()){ 13 | int level = d.size(); //这一层的节点数 14 | while(level--){ 15 | int src = d.front(); 16 | d.pop_front(); 17 | for(int i = nums[src];i >= 1;i--){ 18 | if(src + i >= target) 19 | return ++res; 20 | else if(flags[src + i] == 1) 21 | break; 22 | else { 23 | d.push_back(src + i); 24 | flags[src + i] = 1; 25 | } 26 | } 27 | } 28 | res++; 29 | } 30 | 31 | return -1;//无法到达 32 | } 33 | }; -------------------------------------------------------------------------------- /454.4Sum II/454.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int fourSumCount(vector& A, vector& B, vector& C, vector& D) { 4 | int count = 0; 5 | 6 | unordered_map map; 7 | 8 | for(int num1 : A) 9 | for(int num2 : B) 10 | map[num1+num2]++; 11 | 12 | for(int num3 : C) 13 | for(int num4 : D){ 14 | auto itr = map.find(-num3-num4); 15 | if(itr != map.end()) 16 | count += itr->second; 17 | } 18 | 19 | return count; 20 | } 21 | }; -------------------------------------------------------------------------------- /46.Permutations/46.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> permute(vector& nums) { 4 | vector> res; 5 | 6 | permute(nums,0,res); 7 | 8 | return res; 9 | } 10 | private: 11 | void permute(vector &nums,int idx,vector> &res){ 12 | if(idx == nums.size()) 13 | res.push_back(nums); 14 | 15 | for(int i = idx;i < nums.size();i++){ 16 | int tp = nums[i]; 17 | nums[i] = nums[idx]; 18 | nums[idx] = tp; 19 | 20 | permute(nums,idx + 1,res); 21 | 22 | tp = nums[i]; 23 | nums[i] = nums[idx]; 24 | nums[idx] = tp; 25 | } 26 | } 27 | }; -------------------------------------------------------------------------------- /46.Permutations/README.md: -------------------------------------------------------------------------------- 1 | 和“字符的全排列”一样,数组中的每个元素和后面的元素交换,然后继续处理剩余数组。处理完后恢复交换之前的状态 -------------------------------------------------------------------------------- /47.Permutations II/47.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> permuteUnique(vector& nums) { 4 | vector> res; 5 | 6 | permuteUnique(nums,0,res); 7 | 8 | return res; 9 | } 10 | 11 | private: 12 | void permuteUnique(vector& nums,int idx,vector> &res){ 13 | if(idx == nums.size()){ 14 | res.push_back(nums); 15 | } 16 | 17 | set s; 18 | for(int i = idx;i < nums.size();i++){ 19 | if(s.find(nums[i]) != s.end()) continue; 20 | 21 | s.insert(nums[i]); 22 | 23 | int tp = nums[i]; 24 | nums[i] = nums[idx]; 25 | nums[idx] = tp; 26 | 27 | permuteUnique(nums,idx + 1,res); 28 | 29 | tp = nums[i]; 30 | nums[i] = nums[idx]; 31 | nums[idx] = tp; 32 | } 33 | } 34 | }; -------------------------------------------------------------------------------- /47.Permutations II/README.md: -------------------------------------------------------------------------------- 1 | 用一个set保存已经交换过的元素 2 | 3 | 比如对于序列[1,1,2] 4 | 5 | * 当处理第一个1时,由于set中没有1,所以处理以1开头的排列 6 | * 当处理第二个1时,由于set已经包含了1,即已经处理过相同的排列,所以不交换 7 | * 当处理2时,由于set不包含1,即没有处理以2开头的排列,所以1与2交换 -------------------------------------------------------------------------------- /48.Rotate Image/48.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void rotate(vector>& matrix) { 4 | int n = matrix.size(); 5 | 6 | for(int i = 0;i <= (n-1)/2;i++){ 7 | for(int j = i;j < n - 1 - i;j++){ 8 | int tp = matrix[i][j]; 9 | matrix[i][j] = matrix[n-j-1][i]; 10 | matrix[n-j-1][i] = matrix[n-i-1][n-j-1]; 11 | matrix[n-i-1][n-j-1] = matrix[j][n-i-1]; 12 | matrix[j][n-i-1] = tp; 13 | } 14 | } 15 | } 16 | }; -------------------------------------------------------------------------------- /48.Rotate Image/README.md: -------------------------------------------------------------------------------- 1 | 这个题的主要问题是不能分配额外的矩阵,必须在原矩阵上修改。那么必须保证在将一个元素移动到旋转后的正确位置上之前,目的地位置的元素必须已经旋转至正确位置 2 | 3 | 比如元素matrix\[i\]\[j\],需要旋转至matrix\[j\]\[n-i-1\],而matrix\[j\]\[n-i-1\]又需要旋转至matrix\[n-i-1\]\[n-j-1\],matrix\[n-i-1\]\[n-j-1\]需要旋转至matrix\[n-j-1\]\[i\],matrix\[n-j-1\]\[i\]需要旋转至matrix[i,j],整个坐标旋转映射关系如下: 4 | 5 | (i,j) -> (j,n-i-1) -> (n-i-1,n-j-1) -> (n-j-1,i) -> (i,j) 6 | 7 | 这个旋转轨迹涉及到以(i,i)为左上角,以(n-i-1,n-i-1)为右下角的正方形的4条边上的元素,所以可以使用上面的旋转轨迹,由外向内,每次旋转一个正方形4条边上的所有元素 8 | 9 | -------------------------------------------------------------------------------- /49.Group Anagrams/49.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> groupAnagrams(vector& strs) { 4 | vector> res; 5 | map> mp; 6 | 7 | for(int i = 0;i < strs.size();i++){ 8 | string tp = strs[i]; 9 | sort(tp.begin(),tp.end()); 10 | 11 | if(mp.find(tp) == mp.end()){ 12 | vector v; 13 | v.push_back(strs[i]); 14 | mp.insert(pair>(tp,v)); 15 | } 16 | else{ 17 | mp.find(tp)->second.push_back(strs[i]); 18 | } 19 | } 20 | 21 | for(auto e : mp){ 22 | res.push_back(e.second); 23 | } 24 | 25 | return res; 26 | } 27 | }; -------------------------------------------------------------------------------- /49.Group Anagrams/README.md: -------------------------------------------------------------------------------- 1 | ### 方法一 2 | 3 | 可以比较每个字符串排序后的字符串,字符颠倒的字符串排序后肯定是用一个字符串 4 | 5 | 因此,使用一个map存储“排序后字符串”和“颠倒字符串集合”的映射,key的类型是string,表示排序后的字符串,value是vector\,表示每个“Group Anagrams” 6 | 7 | 对于每个字符串,排序后进行查找,如果找到则插入,否则向map中插入一个新的映射 8 | 9 | 假设参数字符串数组包含N个字符串,最长的字符串包含K个字符 10 | 11 | * **时间复杂度**:O(N\*K\*log(K)) 12 | * **空间复杂度**:O(N\*K) 13 | 14 | ### 方法二 15 | 16 | 同样使用一个map,但是不对字符串进行排序,因此可以提高效率,关键是如何设计key,可以使两个字符颠倒的字符串得到相同的key? 17 | 18 | 由于所有字符颠倒的字符串肯定包含相同的字符,并且每个字符的计数也相同,因此可以对26个小写字母与(题目规定了字符串的字符为小写)进行计数,对于字符串"aabc",包含2个'a',1个'b'和1个'c'。因此key可以设计成"#2#1#1#0#0...#0",这样对于字符串”abac“也会得到相同的key 19 | 20 | 假设参数字符串数组包含N个字符串,最长的字符串包含K个字符 21 | 22 | * **时间复杂度**:O(N\*K) 23 | * **空间复杂度**:O(N\*K) 24 | 25 | [参考](https://leetcode.com/problems/group-anagrams/solution/) -------------------------------------------------------------------------------- /5.Longest Palindromic Substring/5.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | string longestPalindrome(string s) { 4 | if(s.length() <= 1) return s; 5 | 6 | string res = ""; 7 | int j; 8 | for(int i = 0;i < s.length();i = j){ 9 | //向右找到第一个不相同的字符,i~(j-1)为相同字符 10 | for(j = i + 1;j < s.length() && s[j] == s[i];j++) {} 11 | int len = longestPalindrome(s,i,j - 1); 12 | if(len > res.length()) 13 | res = s.substr(i - (len - (j - i)) / 2,len); 14 | } 15 | return res; 16 | } 17 | private: 18 | int longestPalindrome(const string &s,int i,int j){ 19 | int l = i - 1,r = j + 1,len = s.length(); 20 | int count = j - i + 1; 21 | while(l >= 0 && r < len && s[l--] == s[r++]) 22 | count += 2; 23 | return count; 24 | } 25 | }; -------------------------------------------------------------------------------- /50.Pow(x,n)/50.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | double myPow(double x, int n) { 4 | if(x == 0) return 0; 5 | if(n == 0) return 1; 6 | 7 | long long nl = n; 8 | bool negative = nl < 0; 9 | if(negative) nl = nl * -1; 10 | 11 | while((nl & 1) == 0){ 12 | nl >>= 1; 13 | x *= x; 14 | } 15 | 16 | double res = x; 17 | nl >>= 1; 18 | 19 | while(nl){ 20 | x *= x; 21 | if((nl & 1) == 1) res *= x; 22 | nl >>= 1; 23 | } 24 | 25 | if(negative) return 1 / res; 26 | return res; 27 | } 28 | }; -------------------------------------------------------------------------------- /53.Maximum Subarray/53.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int maxSubArray(vector& nums) { 4 | int sum = 0,max = INT_MIN; 5 | for(int num : nums){ 6 | if(sum > 0) sum += num; 7 | else sum = num; 8 | if(sum > max) max = sum; 9 | } 10 | return max; 11 | } 12 | }; -------------------------------------------------------------------------------- /53.Maximum Subarray/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 4 | 5 | 示例: 6 | 7 | ``` 8 | 输入: [-2,1,-3,4,-1,2,1,-5,4], 9 | 输出: 6 10 | 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 11 | ``` 12 | 13 | 14 | ## 解答 15 | 16 | * 如果前一个子数组的和大于0,那么当前元素并入前一个子数组从而组成一个更大的子数组可能会有一个新的更大的值 17 | * 如果前一个子数组的和小于0,那么当前元素不并入前一个子数组可以得到更大的和 18 | 19 | 每次更新得到一个新的和时,与最大值判断,如果大于最大值则更新 20 | 21 | ```c++ 22 | class Solution { 23 | public: 24 | int maxSubArray(vector& nums) { 25 | int sum = 0,max = INT_MIN; 26 | for(int num : nums){ 27 | if(sum > 0) sum += num; 28 | else sum = num; 29 | if(sum > max) max = sum; 30 | } 31 | return max; 32 | } 33 | }; 34 | ``` 35 | -------------------------------------------------------------------------------- /54.Spiral Matrix/54.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector spiralOrder(vector>& matrix) { 4 | if(matrix.empty()) return vector(); 5 | 6 | vector res; 7 | int rows = matrix.size(); 8 | int columns = matrix[0].size(); 9 | 10 | for(int i = 0;i <= (rows - 1) / 2 && i <= (columns - 1) / 2;i++){ 11 | int left = i,right = columns - 1 - left,up = i,down = rows - 1 - up; 12 | for(int j = left;j <= right;j++) 13 | res.push_back(matrix[up][j]); 14 | for(int j = up + 1;j <= down;j++) 15 | res.push_back(matrix[j][right]); 16 | if(up < down) 17 | for(int j = right - 1;j >= left;j--) 18 | res.push_back(matrix[down][j]); 19 | if(right > left) 20 | for(int j = down - 1;j > up;j--){ 21 | res.push_back(matrix[j][left]); 22 | } 23 | } 24 | 25 | return res; 26 | } 27 | }; -------------------------------------------------------------------------------- /54.Spiral Matrix/README.md: -------------------------------------------------------------------------------- 1 | 一圈一圈打印矩阵,外层循环是每圈的左上角的坐标,每圈左上角的坐标位于对角线上,所以x=y 2 | 3 | 使用4个变量up,down,left,right表示每圈的边界坐标 4 | 5 | 打印每圈时,先打印上面一行,再打印右边一列,然后打印下面一行,最后打印左边一列 6 | 7 | 打印下面一行和左边一列时,需要先判断边界: 8 | 9 | * 对于[1,2,3,4],如果不判断边界,会重复打印1,2,3 10 | * 对于[1,2,3,4](旋转成一列),如果不判断边界,也会重复打印1,2,3 -------------------------------------------------------------------------------- /55.Jump Game/55.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool canJump(vector& nums) { 4 | if(nums.empty()) return true; 5 | 6 | int rest = 0;//步长为非负数,这里初始化为0 7 | 8 | int i; 9 | for(i = 0;i < nums.size();i++){ 10 | if(rest == 0 || nums[i] > --rest) rest = nums[i]; 11 | if(rest == 0 && i < nums.size() - 1) return false; 12 | } 13 | 14 | return true; 15 | } 16 | }; -------------------------------------------------------------------------------- /55.Jump Game/README.md: -------------------------------------------------------------------------------- 1 | **贪心**,遍历数组中的每个位置,使用变量rest记录剩余可以前进的步数 2 | 3 | 如果当前位置可以前进的步长大于剩余步长,则更新rest 4 | 5 | 每前进一步rest减一,当rest为0时,更新rest为当前位置可以前进的步长。如果在到达最后位置之前,rest减为0,并且当前位置可以前进的步长也为0,说明无法继续前进,因此返回false 6 | 7 | > 整个过程一直更新rest,保存能前进的最大步长 -------------------------------------------------------------------------------- /56.Merge Intervals/56.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for an interval. 3 | * struct Interval { 4 | * int start; 5 | * int end; 6 | * Interval() : start(0), end(0) {} 7 | * Interval(int s, int e) : start(s), end(e) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector merge(vector& intervals) { 13 | if(intervals.empty()) return vector(); 14 | 15 | //lambda:[capture list] (parameter list) -> return type {function body} 16 | sort(intervals.begin(),intervals.end(),[](const Interval &i1,const Interval &i2){return i1.start < i2.start;}); 17 | 18 | vector res; 19 | res.push_back(intervals[0]); 20 | for(int i = 1;i < intervals.size();i++){ 21 | if(intervals[i].start <= res.back().end) 22 | res.back().end = max(intervals[i].end,res.back().end); 23 | else 24 | res.push_back(intervals[i]); 25 | } 26 | 27 | return res; 28 | } 29 | }; -------------------------------------------------------------------------------- /56.Merge Intervals/README.md: -------------------------------------------------------------------------------- 1 | 先对区间按start进行排序,这保证了每个区间不可能出现在前一个区间之前 2 | 3 | 排序后,对区间进行合并。假设前k个区间已经合并成m个区间,对于区间k+1: 4 | 5 | * 区间k+1的start在合并好的m-1区间的范围内,那么根据区间m-1的end和区间k+1的end判断是否更新区间m-1的end值 6 | * 区间k+1的start在合并好的m-1区间的后面,那么区间k+1单独成为一个独立的区间,添加到合并的m个区间中 -------------------------------------------------------------------------------- /62.Unique Paths/62.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int uniquePaths(int m, int n) { 4 | if(m <= 0 || n <= 0) return 0; 5 | if(m == 1 || n == 1) return 1; 6 | 7 | vector state; 8 | 9 | for(int j = 0;j < n;j++) state.push_back(1); 10 | 11 | for(int i = m - 2;i >= 0;i--){ 12 | for(int j = n - 2;j >= 0;j--){ 13 | //状态转移方程 14 | state[j] = state[j+1] + state[j]; 15 | } 16 | } 17 | 18 | return state[0]; 19 | } 20 | }; -------------------------------------------------------------------------------- /66.Plus One/66.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector plusOne(vector& digits) { 4 | int jw = 0,sz = digits.size(); 5 | int i = sz - 1; 6 | while(i >= 0 && digits[i] == 9){ 7 | digits[i] = 0; 8 | i--; 9 | } 10 | if(i >= 0) digits[i] += 1; 11 | else{ 12 | digits[0] = 1; 13 | digits.push_back(0); 14 | } 15 | 16 | return digits; 17 | } 18 | }; -------------------------------------------------------------------------------- /66.Plus One/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个非负整数组成的非空数组,在该数的基础上加一,返回一个新的数组。 4 | 5 | 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。 6 | 7 | 你可以假设除了整数 0 之外,这个整数不会以零开头。 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 输入: [1,2,3] 13 | 输出: [1,2,4] 14 | 解释: 输入数组表示数字 123。 15 | ``` 16 | 17 | 示例 2: 18 | 19 | ``` 20 | 输入: [4,3,2,1] 21 | 输出: [4,3,2,2] 22 | 解释: 输入数组表示数字 4321。 23 | ``` 24 | 25 | ## 解答 26 | 27 | 从数组最后一个数往前处理,如果数字等于9,那么表示变为0,然后进位,前一位因此也需要进行加1处理,直到某个数字小于9或者已经处理完数组的所有数字。如果所有数字都是9,那么需要在数组最前面添加一个1,可以将首元素改为1,然后压入一个0 28 | 29 | ```c++ 30 | class Solution { 31 | public: 32 | vector plusOne(vector& digits) { 33 | int jw = 0,sz = digits.size(); 34 | int i = sz - 1; 35 | while(i >= 0 && digits[i] == 9){ 36 | digits[i] = 0; 37 | i--; 38 | } 39 | if(i >= 0) digits[i] += 1; 40 | else{ 41 | digits[0] = 1; 42 | digits.push_back(0); 43 | } 44 | 45 | return digits; 46 | } 47 | }; 48 | ``` -------------------------------------------------------------------------------- /69.Sqrtx/69.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int mySqrt(int x) { 4 | if(x < 0 || x == 0) return 0; 5 | 6 | int l = 1,r = INT_MAX; 7 | while(true){ 8 | int mid = l + ((r - l) >> 1); 9 | if(mid > x / mid) //mid * mid > x,继续往左边找 10 | r = mid - 1; 11 | else{ //mid * mid <= x 12 | if(mid + 1 > x / (mid + 1)) 13 | return mid; 14 | l = mid + 1; 15 | } 16 | } 17 | } 18 | }; -------------------------------------------------------------------------------- /69.Sqrtx/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 实现 int sqrt(int x) 函数。 4 | 5 | 计算并返回 x 的平方根,其中 x 是非负整数。 6 | 7 | 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 输入: 4 13 | 输出: 2 14 | ``` 15 | 16 | 示例 2: 17 | 18 | ``` 19 | 输入: 8 20 | 输出: 2 21 | 说明: 8 的平方根是 2.82842..., 22 | 由于返回类型是整数,小数部分将被舍去。 23 | ``` 24 | 25 | ## 解答 26 | 27 | 在INT范围内进行二分查找 28 | 29 | 需要特别注意的是,如果使用res * res 与 x进行比较,那么res * res可能会溢出 30 | 31 | ```c++ 32 | class Solution { 33 | public: 34 | int mySqrt(int x) { 35 | if(x < 0 || x == 0) return 0; 36 | 37 | int l = 1,r = INT_MAX; 38 | while(true){ 39 | int mid = l + ((r - l) >> 1); 40 | if(mid > x / mid) //mid * mid > x,继续往左边找 41 | r = mid - 1; 42 | else{ //mid * mid <= x 43 | if(mid + 1 > x / (mid + 1)) 44 | return mid; 45 | l = mid + 1; 46 | } 47 | } 48 | } 49 | }; 50 | ``` -------------------------------------------------------------------------------- /695.Max Area of Island/695.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * DFS 3 | */ 4 | 5 | class Solution { 6 | public: 7 | int maxAreaOfIsland(vector>& grid) { 8 | if(grid.size() == 0) 9 | return 0; 10 | 11 | int res = 0; 12 | int rows = grid.size(),columns = grid[0].size(); 13 | for(int i = 0;i < rows;i++){ 14 | for(int j = 0;j < columns;j++){ 15 | if(grid[i][j] == 1){ 16 | int area = DFS(grid,i,j,rows,columns); 17 | res = area > res ? area : res; 18 | } 19 | } 20 | } 21 | 22 | return res; 23 | } 24 | 25 | int DFS(vector> &grid,int row,int column,int rows,int columns){ 26 | //越界或者不连通 27 | if(row < 0 || row >= rows || column < 0 || column >= columns || grid[row][column] == 0) 28 | return 0; 29 | 30 | int count = 1; 31 | grid[row][column] = 0;//防止重复计算 32 | /*遍历该顶点的四个方向*/ 33 | count += DFS(grid,row - 1,column,rows,columns); 34 | count += DFS(grid,row + 1,column,rows,columns); 35 | count += DFS(grid,row,column - 1,rows,columns); 36 | count += DFS(grid,row,column + 1,rows,columns); 37 | 38 | return count; 39 | } 40 | }; -------------------------------------------------------------------------------- /695.Max Area of Island/README.md: -------------------------------------------------------------------------------- 1 | 典型的DFS,遍历图中的节点,如果值为1则使用DFS计算该岛屿的面积,更新最大面积 2 | 3 | 为了防止重复计算和无限循环,每计算一个顶点将其设置为0 -------------------------------------------------------------------------------- /7.Reverse Integer/7.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int reverse(int x) { 4 | long long res = 0,num = x; 5 | bool negative = (num < 0); 6 | if(negative) num *= -1; 7 | while(num){ 8 | res = res * 10 + (num % 10); 9 | num = num / 10; 10 | if(res > INT_MAX){ 11 | if(!negative) return 0; 12 | if(res - 1 > INT_MAX) return 0; 13 | } 14 | } 15 | if(negative) res *= -1; 16 | return res; 17 | } 18 | }; -------------------------------------------------------------------------------- /7.Reverse Integer/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定一个 32 位有符号整数,将整数中的数字进行反转。 4 | 5 | 示例 1: 6 | 7 | ``` 8 | 输入: 123 9 | 输出: 321 10 | ``` 11 | 12 | 示例 2: 13 | 14 | ``` 15 | 输入: -123 16 | 输出: -321 17 | ``` 18 | 19 | 示例 3: 20 | 21 | ``` 22 | 输入: 120 23 | 输出: 21 24 | ``` 25 | 26 | 注意: 27 | 28 | 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0 29 | 30 | ## 解答 31 | 32 | 每计算一次结果先乘以10,每次对10取模,加入结果中。注意溢出 33 | 34 | ```c++ 35 | class Solution { 36 | public: 37 | int reverse(int x) { 38 | long long res = 0,num = x; 39 | bool negative = (num < 0); 40 | if(negative) num *= -1; 41 | while(num){ 42 | res = res * 10 + (num % 10); 43 | num = num / 10; 44 | if(res > INT_MAX){ 45 | if(!negative) return 0; 46 | if(res - 1 > INT_MAX) return 0; 47 | } 48 | } 49 | if(negative) res *= -1; 50 | return res; 51 | } 52 | }; 53 | ``` -------------------------------------------------------------------------------- /70.Climbing Stairs/70.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int climbStairs(int n) { 4 | if(n <= 0) return 0; 5 | if(n == 1) return 1; 6 | if(n == 2) return 2; 7 | 8 | int count1 = 1,count2 = 2,count; 9 | for(int i = 3;i <= n;i++){ 10 | count = count1 + count2; 11 | count1 = count2; 12 | count2 = count; 13 | } 14 | 15 | return count; 16 | } 17 | }; -------------------------------------------------------------------------------- /70.Climbing Stairs/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 假设你正在爬楼梯。需要 n 步你才能到达楼顶。 4 | 5 | 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 6 | 7 | 注意:给定 n 是一个正整数。 8 | 9 | 示例 1: 10 | 11 | ``` 12 | 输入: 2 13 | 输出: 2 14 | 解释: 有两种方法可以爬到楼顶。 15 | 1. 1 步 + 1 步 16 | 2. 2 步 17 | ``` 18 | 19 | 示例 2: 20 | 21 | ``` 22 | 输入: 3 23 | 输出: 3 24 | 解释: 有三种方法可以爬到楼顶。 25 | 1. 1 步 + 1 步 + 1 步 26 | 2. 1 步 + 2 步 27 | 3. 2 步 + 1 步 28 | ``` 29 | 30 | ## 解答 31 | 32 | 假设n级楼梯有f(n)种爬法,因为第一次可以选择爬1步或者爬2步,因此: 33 | 34 | * 如果第一次爬1步,那么剩下n-1级楼梯有f(n-1)种爬法 35 | * 如果第一次爬2步,那么剩下n-2级楼梯有f(n-2)种爬法 36 | 37 | 故:f(n) = f(n - 1) + f(n - 2) 38 | 39 | ```c++ 40 | class Solution { 41 | public: 42 | int climbStairs(int n) { 43 | if(n <= 0) return 0; 44 | if(n == 1) return 1; 45 | if(n == 2) return 2; 46 | 47 | int count1 = 1,count2 = 2,count; 48 | for(int i = 3;i <= n;i++){ 49 | count = count1 + count2; 50 | count1 = count2; 51 | count2 = count; 52 | } 53 | 54 | return count; 55 | } 56 | }; 57 | ``` 58 | -------------------------------------------------------------------------------- /73.Set Matrix Zeroes/73.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void setZeroes(vector>& matrix) { 4 | bool col0 = false; 5 | int rows = matrix.size(); 6 | int columns = rows > 0 ? matrix[0].size() : 0; 7 | 8 | for(int i = 0;i < rows;i++){ 9 | if(matrix[i][0] == 0) col0 = true; 10 | for(int j = 1;j < columns;j++){ 11 | if(matrix[i][j] == 0) 12 | matrix[i][0] = matrix[0][j] = 0; 13 | } 14 | } 15 | 16 | for(int j = 1;j < columns;j++) 17 | if(matrix[0][j] == 0) 18 | for(int i = 1;i < rows;i++) 19 | matrix[i][j] = 0; 20 | 21 | for(int i = 0;i < rows;i++) 22 | if(matrix[i][0] == 0) 23 | for(int j = 1;j < columns;j++) 24 | matrix[i][j] = 0; 25 | 26 | if(col0) 27 | for(int i = 0;i < rows;i++) 28 | matrix[i][0] = 0; 29 | 30 | } 31 | }; -------------------------------------------------------------------------------- /75.Sort Colors/75.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void sortColors(vector& nums) { 4 | int redcount = 0, whitecount = 0; 5 | 6 | for(int i = 0;i < nums.size();i++){ 7 | if (nums[i] == 0) 8 | redcount++; 9 | else if(nums[i] == 1) 10 | whitecount++; 11 | else if(nums[i] == 2) 12 | continue; 13 | else 14 | return; 15 | } 16 | 17 | for(int i = 0;i map; 5 | for(char c : t) map[c]++; 6 | 7 | int start = 0,i = 0,min = INT_MAX; 8 | int len = s.length(),total = t.length(); 9 | for(int j = 0;j < s.length();j++){ 10 | if(map.find(s[j]) != map.end())//如果遇到一个t中的字符 11 | if(map[s[j]]-- > 0) 12 | total--; 13 | while(total == 0){//说明当前滑动窗口覆盖了t中的所有字符 14 | if(j - i + 1 < min){ 15 | min = j - i + 1; 16 | start = i; //更新start的位置 17 | } 18 | //从滑动窗口左边回收字符,寻找下一个满足条件的滑动窗口 19 | //如果t中某些字符在滑动窗口中出现了多次,对于map中的计数会<0 20 | //如果++没有大于0,说明是遇到一个在滑动窗口中出现多次的字符 21 | //因此不增加total 22 | if(map.find(s[i]) != map.end()){ 23 | if(++map[s[i++]] > 0) 24 | total++; 25 | } 26 | else i++; 27 | } 28 | } 29 | 30 | return min == INT_MAX ? "" : s.substr(start,min); 31 | } 32 | }; -------------------------------------------------------------------------------- /78.Subsets/78.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | vector> subsets(vector& nums) { 4 | vector subset; 5 | vector> res; 6 | subsets(nums,0,res,subset); 7 | return res; 8 | } 9 | 10 | private: 11 | void subsets(const vector &nums,int idx,vector> &res,vector subset){ 12 | if(idx < 0) return; 13 | else if(idx == nums.size()){ 14 | res.push_back(subset); 15 | return; 16 | } 17 | 18 | subset.push_back(nums[idx]); 19 | subsets(nums,idx + 1,res,subset); 20 | subset.pop_back(); 21 | subsets(nums,idx + 1,res,subset); 22 | } 23 | }; -------------------------------------------------------------------------------- /78.Subsets/README.md: -------------------------------------------------------------------------------- 1 | 对于每个元素,可以选择要或者不要 2 | 3 | * 如果要,子集等于该元素加上剩余元素的所有子集 4 | * 如果不要,子集等于剩余元素的所有子集 -------------------------------------------------------------------------------- /79.Word Search/79.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool exist(vector>& board, string word) { 4 | if(board.empty()) return word.empty(); 5 | if(word.empty()) return true; 6 | 7 | 8 | vector> flags; 9 | for(int i = 0;i < board.size();i++){ 10 | vector tp; 11 | for(int j = 0;j < board[0].size();j++) 12 | tp.push_back(0); 13 | flags.push_back(tp); 14 | } 15 | 16 | for(int i = 0;i < board.size();i++){ 17 | for(int j = 0;j < board[0].size();j++) 18 | if(exist(board,flags,word,i,j,0)) 19 | return true; 20 | } 21 | 22 | return false; 23 | } 24 | 25 | private: 26 | bool exist(vector>& board, vector> &flags,string word,int row,int col,int idx){ 27 | if(idx == word.size()) return true; 28 | 29 | if(row < 0 || row >= board.size() || col < 0 || col >= board[0].size() || 30 | flags[row][col] == 1 || board[row][col] != word[idx]) 31 | return false; 32 | 33 | flags[row][col] = 1; 34 | bool ret = exist(board,flags,word,row + 1,col,idx + 1) || exist(board,flags,word,row - 1,col,idx + 1) 35 | || exist(board,flags,word,row,col + 1,idx + 1) || exist(board,flags,word,row,col - 1,idx + 1); 36 | flags[row][col] = 0; 37 | return ret; 38 | } 39 | }; -------------------------------------------------------------------------------- /79.Word Search/README.md: -------------------------------------------------------------------------------- 1 | > 同《剑指offer》面试题12 2 | 3 | * 如果查找字符串为空,直接返回ture 4 | * 如果字符矩阵为空,那么只有当查找字符串也为空时,才返回true 5 | * 否则,是一次常规的查找 6 | 7 | 循环,以字符矩阵每一位置为起始位置,判断能否查找到字符串: 8 | 9 | * 如果越界,或者当前位置已经走过,或者当前位置的字符和当前字符串中所需查找的字符不等 ,则直接返回false 10 | * 否则,如果当前位置的字符等于当前字符串中所需查找的字符,那么标记这个位置为已经走过,继续从4个方向进行剩余字符的查找 11 | 12 | idx记录当前字符串中所需查找的字符,如果已经查找到字符串的最后一个字符,接下来idx会等于word.size(),那么说明已经找到,因此返回true 13 | 14 | 每次以字符矩阵一个位置为起始位置进行查找时,要求flags矩阵所有元素都为0,即没有走过,所以在每次查找过程中,走过一个位置后,需要清理相应位置的标记 -------------------------------------------------------------------------------- /8.String to Integer/8.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int myAtoi(string str) { 4 | int i = 0; 5 | //找到第一个不为' '的位置 6 | for(;i < str.length() && str[i] == ' ';i++) ; 7 | if(i >= str.length()) return 0; 8 | 9 | bool negative = (str[i] == '-'); 10 | if(str[i] == '+' || str[i] == '-') i++; 11 | 12 | long long res = 0; 13 | for(;i < str.length();i++){ 14 | if(str[i] > '9' || str[i] < '0') break; 15 | res = res * 10 + (str[i] - '0'); 16 | if(res > INT_MAX){ 17 | if(!negative) return INT_MAX; 18 | if(res - 1 > INT_MAX) return INT_MIN; 19 | } 20 | } 21 | 22 | if(negative) res *= -1; 23 | return (int)res; 24 | } 25 | }; -------------------------------------------------------------------------------- /83.Remove Duplicates from Sorted List/83.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * struct ListNode { 4 | * int val; 5 | * ListNode *next; 6 | * ListNode(int x) : val(x), next(NULL) {} 7 | * }; 8 | */ 9 | class Solution { 10 | public: 11 | ListNode* deleteDuplicates(ListNode* head) { 12 | ListNode **curr = &head,*tp; 13 | 14 | while(*curr){//当前节点不为NULL 15 | if((*curr)->next && (*curr)->val == (*curr)->next->val){ 16 | tp = (*curr)->next; 17 | (*curr)->next = tp->next; 18 | tp->next = NULL; 19 | } 20 | else 21 | curr = &((*curr)->next); 22 | } 23 | 24 | return head; 25 | } 26 | }; -------------------------------------------------------------------------------- /83.Remove Duplicates from Sorted List/README.md: -------------------------------------------------------------------------------- 1 | ## 思路 2 | 3 | 使用指针的指针curr记录指向当前节点指针的地址。指针的指针可以解引用得到指向当前节点的指针,然后可以进一步修改其next成员,指向删除节点的后一节点,实现节点删除 4 | 5 | 每次处理开始先解引用curr,检查指向当前节点的指针是否为空,为空说明链表为空或者到达链表结尾,此时处理完成。否则,说明当前节点不为空,需要进一步处理: 6 | 7 | * 如果当前节点中,存在下一个节点的指针(即next成员非空)并且当前节点的值和下一节点的值相等,则删除下一节点,用临时指针tp记录删除节点的地址,然后更新链表 8 | 9 | * 否则,说明下一节点不能删除或者下一节点为空,因此修改curr的值,使其保存指向下一节点的指针的地址。 10 | 11 | 需要从链表头遍历到链表结尾,时间代价为n 12 | 13 | -------------------------------------------------------------------------------- /84.Largest Rectangle in Histogram/84.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int largestRectangleArea(vector& heights) { 4 | heights.push_back(0); //保证最后一次处理 5 | stack s; 6 | int max_area = 0; 7 | for(int i = 0;i < heights.size();i++){ 8 | while(!s.empty() && heights[i] <= heights[s.top()]){ 9 | int height = heights[s.top()]; 10 | s.pop(); 11 | int idx = s.empty() ? -1 : s.top(); 12 | int width = i - idx - 1; 13 | if(width * height > max_area) max_area = width * height; 14 | } 15 | s.push(i); 16 | } 17 | 18 | return max_area; 19 | } 20 | }; -------------------------------------------------------------------------------- /84.Largest Rectangle in Histogram/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 4 | 5 | 求在该柱状图中,能够勾勒出来的矩形的最大面积 6 | 7 |
8 | 9 | 示例: 10 | 11 | ``` 12 | 输入: [2,1,5,6,2,3] 13 | 输出: 10 14 | ``` 15 | 16 | ## 解答 17 | 18 | 使用一个栈保存高度: 19 | 20 | 1. 升序时,压入栈中 21 | 2. 发生降序时,从栈顶弹出元素,计算,并且根据计算结果更新最大矩阵的值。重复这个过程直到栈中的高度重新保持升序 22 | 23 | 以题目中的示例,当遇到1,2,0(这个是添加到heights末尾的元素,为的是保证最后一次计算)时会进行计算,每次会计算的面积以图中的虚线表示: 24 | 25 |
26 | 27 | ```c++ 28 | class Solution { 29 | public: 30 | int largestRectangleArea(vector& heights) { 31 | heights.push_back(0); //保证最后一次处理 32 | stack s; 33 | int max_area = 0; 34 | for(int i = 0;i < heights.size();i++){ 35 | while(!s.empty() && heights[i] <= heights[s.top()]){ 36 | int height = heights[s.top()]; 37 | s.pop(); 38 | int idx = s.empty() ? -1 : s.top(); 39 | int width = i - idx - 1; 40 | if(width * height > max_area) max_area = width * height; 41 | } 42 | s.push(i); 43 | } 44 | 45 | return max_area; 46 | } 47 | }; 48 | ``` -------------------------------------------------------------------------------- /88.Merge Sorted Array/88.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | void merge(vector& nums1, int m, vector& nums2, int n) { 4 | if(nums1.empty() || nums2.empty() || m < 0 || n < 0) return ; 5 | 6 | int end1 = m - 1,end2 = n - 1,end = nums1.size() - 1; 7 | while(end1 >= 0 && end2 >= 0){ 8 | if(nums1[end1] >= nums2[end2]) 9 | nums1[end--] = nums1[end1--]; 10 | else 11 | nums1[end--] = nums2[end2--]; 12 | } 13 | 14 | while(end2 >= 0) 15 | nums1[end--] = nums2[end2--]; 16 | } 17 | }; -------------------------------------------------------------------------------- /88.Merge Sorted Array/README.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 4 | 5 | 说明: 6 | 7 | * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 8 | * 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 9 | 10 | 示例: 11 | 12 | ``` 13 | 输入: 14 | nums1 = [1,2,3,0,0,0], m = 3 15 | nums2 = [2,5,6], n = 3 16 | 17 | 输出: [1,2,2,3,5,6] 18 | ``` 19 | 20 | ## 解答 21 | 22 | 如果从前往后合并,那么可能会覆盖nums1中还未合并的元素,因此从后往前合并。 23 | 24 | 使用3个变量,end1指向nums1中需要合并的尾元素的位置,end2指向nums2中需要合并的尾元素的位置,end指向nums1的末尾。每次从end1和end2指向元素中选出较大者,插入end位置: 25 | 26 | ```c++ 27 | class Solution { 28 | public: 29 | void merge(vector& nums1, int m, vector& nums2, int n) { 30 | if(nums1.empty() || nums2.empty() || m < 0 || n < 0) return ; 31 | 32 | int end1 = m - 1,end2 = n - 1,end = nums1.size() - 1; 33 | while(end1 >= 0 && end2 >= 0){ 34 | if(nums1[end1] >= nums2[end2]) 35 | nums1[end--] = nums1[end1--]; 36 | else 37 | nums1[end--] = nums2[end2--]; 38 | } 39 | 40 | while(end2 >= 0) 41 | nums1[end--] = nums2[end2--]; 42 | } 43 | }; 44 | ``` -------------------------------------------------------------------------------- /91.Decode Ways/91.cpp: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | int numDecodings(string s) { 4 | if(s.size() == 0) return 0; 5 | else if(s.size() == 1) return s[0] == '0' ? 0 : 1; 6 | 7 | int end = s.size() - 1; 8 | int state1 = s[end] == '0' ? 0 : 1 , state2 = 1; 9 | int res; 10 | for(int i = end - 1;i >= 0; i--){ 11 | if(s[i] == '0') res = 0; 12 | else if(stoi(s.substr(i,2)) > 26) res = state1; 13 | else res = state1 + state2; 14 | state2 = state1; 15 | state1 = res; 16 | } 17 | return res; 18 | } 19 | }; -------------------------------------------------------------------------------- /91.Decode Ways/README.md: -------------------------------------------------------------------------------- 1 | 动态规划,考虑包含n个字符的字符串s[0,1,...,n-1] 2 | 3 | * 如果将第一个字符单独解码,设字符串s[1,2,...,n-1]的解码方式有state1种 4 | * 如果能将前两个字符一起解码,设字符串s[2,3,...,n-1]的解码方式有state2种 5 | 6 | 因此,可以得到一个状态转移方程: 7 | 8 | * F(s[0,1,...,n-1]) = state1 (不能将前2个字符一起解码时) 9 | * F(s[0,1,...,n-1]) = state1 + state2 (能将前2个字符一起解码时) 10 | * 还有一种情况,就是如果字符串以‘0’开头,那么单独的‘0’或‘0X’这种形式都无法解码,所以F(s[0,1,...,n-1]) = 0 -------------------------------------------------------------------------------- /94.Binary Tree Inorder Traversal/94.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | vector inorderTraversal(TreeNode* root) { 13 | vector res; 14 | 15 | stack st; 16 | if(root) 17 | st.push(root); 18 | 19 | TreeNode *curr = root; 20 | while(curr || !st.empty()){ 21 | if(curr){ 22 | if(curr->left) 23 | st.push(curr->left); 24 | curr = curr->left; 25 | } 26 | else{ 27 | TreeNode *nd = st.top(); 28 | st.pop(); 29 | res.push_back(nd->val); 30 | if(nd->right){ 31 | curr = nd -> right; 32 | st.push(curr); 33 | } 34 | } 35 | } 36 | 37 | return res; 38 | } 39 | }; -------------------------------------------------------------------------------- /98.Validate Binary Search Tree/98.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * struct TreeNode { 4 | * int val; 5 | * TreeNode *left; 6 | * TreeNode *right; 7 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 | * }; 9 | */ 10 | class Solution { 11 | public: 12 | bool isValidBST(TreeNode* root) { 13 | int *prev = nullptr; 14 | return isValidBST(root,&prev); 15 | } 16 | 17 | bool isValidBST(TreeNode* node,int **pprev){ 18 | if(!node) 19 | return true; 20 | 21 | bool res = isValidBST(node->left,pprev); 22 | 23 | if(*pprev) 24 | res = res && (node->val > **pprev); 25 | *pprev = &(node->val); 26 | 27 | res = res && isValidBST(node->right,pprev); 28 | 29 | return res; 30 | } 31 | }; -------------------------------------------------------------------------------- /98.Validate Binary Search Tree/README.md: -------------------------------------------------------------------------------- 1 | ### 误区 2 | 3 | 这个题一开始想当然了,对于节点node,如果 4 | 5 | 1. node-val > node->left->val; 6 | 2. node->val < node->right->val; 7 | 8 | 那么继续判断左右子树是否满足该性质,如果满足,那么该树就是一棵BST 9 | 10 | 但是这种方法只满足局部BST性质,举例来说: 11 | 12 | ``` 13 | 2 14 | / \ 15 | 1 5 16 | / \ / \ 17 | 0 3 4 6 18 | ``` 19 | 20 | 这个例子满足上面的性质: 21 | 22 | * 对于节点2,其左子节点小于2,右子节点大于2 23 | * 节点1的左子节点小于1,右子节点大于1 24 | * 5的左子节点小于5,右子节点大于6 25 | 26 | 如果按照上面的逻辑,会判断这棵树是BST,但是在根节点2的左子树中,存在节点3,大于根节点2,所以实际上并不是一棵BST 27 | 28 | ### 解法 29 | 30 | 中序遍历,如果是BST,那么中序遍历序列一定是递增的序列,只需要用一个变量维护已经遍历过的序列的最后一个值prev,通过比较当前节点的值和prev,如果依然满足递增的性质,那么继续判断,否则返回false -------------------------------------------------------------------------------- /ContainerWithMostWater.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define min(a,b) ((a) < (b) ? (a) : (b)) 5 | #define max(a,b) ((a) > (b) ? (a) : (b)) 6 | 7 | int maxArea(int* height, int heightSize) { 8 | int l = 0; 9 | int r = heightSize - 1; 10 | int area = 0; 11 | 12 | while(l < r){ 13 | area = max(area,(r - l) * min(height[l],height[r])); 14 | 15 | if(height[l] < height[r]){ 16 | int old_value = height[l]; 17 | while(++l < r && height[l] <= old_value){} 18 | } 19 | else{ 20 | int old_value = height[r]; 21 | while(--r > l && height[r] <= old_value){} 22 | } 23 | } 24 | 25 | return area; 26 | } 27 | 28 | int main(){ 29 | int a[] = {1,8,6,2,5,4,8,3,7}; 30 | 31 | printf("%d\n",maxArea(a,9)); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /IntegerToRoman.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define LENGTH 4 6 | 7 | char* intToRoman(int num){ 8 | int index[LENGTH]; 9 | int i; 10 | char *result = (char*)malloc(sizeof(char) * 16); 11 | char* c[4][10]={ 12 | {"","I","II","III","IV","V","VI","VII","VIII","IX"}, 13 | {"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"}, 14 | {"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"}, 15 | {"","M","MM","MMM"} 16 | }; 17 | 18 | memset(result,'\0',16); 19 | 20 | i = 0; 21 | while(num){ 22 | index[i++] = num % 10; 23 | num /= 10; 24 | } 25 | 26 | i--; 27 | while(i >= 0){ 28 | strcat(result,c[i][index[i]]); 29 | i--; 30 | } 31 | 32 | return result; 33 | } 34 | 35 | int main(){ 36 | //printf("%s\n",intToRoman(1)); 37 | char *str = (char*)malloc(16); 38 | int *a = (int*)malloc(16 * sizeof(int)); 39 | for(int i = 0;i < 16;i++){ 40 | printf("%d %d\n",i,str[i] == '\0'); 41 | printf("%d: a:%d\n",i,a[i]); 42 | printf("%d: str:%c\n",i,str[i]); 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /PalindromeNumber.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include //不然bool类型会报错 4 | 5 | bool isPalindrome(int x); 6 | 7 | int main(){ 8 | printf("%d\n",isPalindrome(12321)); 9 | 10 | return 0; 11 | } 12 | 13 | bool isPalindrome(int x){ 14 | int newResult = 0; 15 | int palindrome = 0; 16 | int y = x; 17 | 18 | while(x){ 19 | newResult = palindrome * 10 + x % 10; 20 | if(newResult / 10 != palindrome ) return false; 21 | palindrome = newResult; 22 | x /= 10; 23 | } 24 | 25 | return palindrome == y ? true : false; 26 | } 27 | -------------------------------------------------------------------------------- /RegularExpressionMatch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool solution(char *s,char *p); 6 | 7 | int main(){ 8 | printf("%d\n",solution("abc","c*a*b*c**")); 9 | return 0; 10 | } 11 | 12 | bool solution(char *s,char *p){ 13 | int length_1 = 0; 14 | int length_2 = 0; 15 | bool **dp; 16 | 17 | for(int i = 0;;i++){ 18 | if(s[i] == '\0') 19 | break; 20 | length_1++; 21 | } 22 | 23 | for(int j = 0;;j++){ 24 | if(p[j] == '\0') 25 | break; 26 | length_2++; 27 | } 28 | 29 | dp = (bool **)malloc((length_1 + 1) * sizeof(bool *)); 30 | for(int i = 0;i <= length_1;i++) 31 | dp[i] = (bool *)malloc((length_2 + 1) * sizeof(bool)); 32 | 33 | dp[0][0] = true; 34 | 35 | for(int i = 1;i <= length_1;i++){ 36 | dp[i][0] = false; 37 | } 38 | 39 | for(int j = 1;j <= length_2;j++){ 40 | //d[0][j] = false,因此d[0][奇数] = false; 41 | dp[0][j] = j > 1 && p[j - 1] == '*' && dp[0][j-2]; 42 | } 43 | 44 | for(int j = 1;j <= length_2;j++){ 45 | for(int i = 1;i <= length_1;i++){ 46 | if(p[j - 1] == '*') 47 | dp[i][j] = j > 1 && (dp[i][j - 2] || (p[j - 2] == '.' || p[j - 2] == s[i - 1]) && dp[i - 1][j]); 48 | else 49 | dp[i][j] = (p[j - 1] == s[i - 1] || p[j - 1] == '.') && dp[i - 1][j - 1]; 50 | } 51 | } 52 | 53 | return dp[length_1][length_2]; 54 | } 55 | -------------------------------------------------------------------------------- /RomanToInteger.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int romanToInt(char* s){ 5 | int map[128]; 6 | int prev; 7 | int rs = 0; 8 | 9 | map['I'] = 1; 10 | map['V'] = 5; 11 | map['X'] = 10; 12 | map['L'] = 50; 13 | map['C'] = 100; 14 | map['D'] = 500; 15 | map['M'] = 1000; 16 | 17 | prev = map[*s]; 18 | while(*s != '\0'){ 19 | if(map[*s] > prev) 20 | rs += map[*s] - 2 * prev; 21 | else 22 | rs += map[*s]; 23 | prev = map[*s]; 24 | s++; 25 | } 26 | 27 | return rs; 28 | } 29 | 30 | int main(){ 31 | printf("%d\n",romanToInt("XCVIII")); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /ZigZag.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char* convert(char* s,int numRows); 5 | 6 | int main(){ 7 | printf("%s\n",convert("abcd",2)); 8 | 9 | return 0; 10 | } 11 | /**/ 12 | char * convert(char* s,int numRows){ 13 | if(numRows <= 1) return s; 14 | 15 | int length = 0; 16 | char* c = s; 17 | while(*c++ != '\0') {length++;} 18 | 19 | char *ans = (char*)malloc(sizeof(char) * length + 1); 20 | ans[length] = '\0'; 21 | 22 | int row_index = 1; 23 | int index1; 24 | int index2 = 0; 25 | while(row_index <= numRows){ 26 | index1 = row_index; 27 | int increment = 2 * (numRows - 1); 28 | int inc = 2 * (numRows - row_index); 29 | 30 | while(index1 <= length){ 31 | ans[index2] = s[index1-1]; 32 | 33 | if(inc > 0) index2++; 34 | 35 | index1 += inc; 36 | inc = increment - inc; 37 | } 38 | 39 | row_index++; 40 | } 41 | 42 | return ans; 43 | } 44 | -------------------------------------------------------------------------------- /img/118.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/118.png -------------------------------------------------------------------------------- /img/127-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/127-1.png -------------------------------------------------------------------------------- /img/127-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/127-2.png -------------------------------------------------------------------------------- /img/127-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/127-3.png -------------------------------------------------------------------------------- /img/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/128.png -------------------------------------------------------------------------------- /img/14-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/14-1.png -------------------------------------------------------------------------------- /img/14-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/14-2.png -------------------------------------------------------------------------------- /img/146.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/146.png -------------------------------------------------------------------------------- /img/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/17.png -------------------------------------------------------------------------------- /img/21-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/21-1.png -------------------------------------------------------------------------------- /img/21-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/21-2.png -------------------------------------------------------------------------------- /img/218-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/218-1.png -------------------------------------------------------------------------------- /img/218-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/218-2.png -------------------------------------------------------------------------------- /img/218-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/218-3.png -------------------------------------------------------------------------------- /img/218.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/218.png -------------------------------------------------------------------------------- /img/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/24.png -------------------------------------------------------------------------------- /img/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/26.png -------------------------------------------------------------------------------- /img/341.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/341.png -------------------------------------------------------------------------------- /img/42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/42.png -------------------------------------------------------------------------------- /img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/5.png -------------------------------------------------------------------------------- /img/73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/73.png -------------------------------------------------------------------------------- /img/84-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/84-1.png -------------------------------------------------------------------------------- /img/84.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arkingc/leetcode/7cd32e89ee38cb1853e49ac81970b90bbc5b9d2b/img/84.png --------------------------------------------------------------------------------