剑指offer题解(第二版)
实现哈希表,好多人碰到了这个,加在这里
705. 设计哈希集合 - 力扣(LeetCode) (leetcode-cn.com)
1 class MyHashSet { 2 private: 3 static const int base = 769; 4 vector<list<int>> data; 5 static int hash(int key) { 6 return key % base; 7 } 8 public: 9 /** Initialize your data structure here. */ 10 MyHashSet(): data(base) {} 11 12 void add(int key) { 13 int h = hash(key); 14 for (auto it = data[h].begin(); it != data[h].end(); it++) { 15 if ((*it) == key) { 16 return; 17 } 18 } 19 data[h].push_back(key); 20 } 21 22 void remove(int key) { 23 int h = hash(key); 24 for (auto it = data[h].begin(); it != data[h].end(); it++) { 25 if ((*it) == key) { 26 data[h].erase(it); 27 return;//不加报错 28 } 29 } 30 } 31 bool contains(int key) { 32 int h = hash(key); 33 for (auto it = data[h].begin(); it != data[h].end(); it++) { 34 if ((*it) == key) { 35 return true; 36 } 37 } 38 return false; 39 } 40 };
剑指 Offer 03. 数组中重复的数字 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int findRepeatNumber(vector<int>& nums) { 4 int a[100000] = {0}; 5 for(int i=0;i<nums.size();i++){ 6 if(a[nums[i]] == 1) 7 return nums[i]; 8 a[nums[i]] = 1; 9 } 10 return 0; 11 } 12 };
剑指 Offer 04. 二维数组中的查找 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool ans = false; 4 void f(vector<vector<int>>& matrix,vector<vector<int>>& vis,int target,int x,int y){ 5 if(x>=matrix.size()||y>=matrix[0].size()) 6 return ; 7 if(vis[x][y]) 8 return ; 9 vis[x][y] = 1; 10 if(target == matrix[x][y]){ 11 ans = true; 12 return ; 13 } 14 if(x+1 < matrix.size()&&target >= matrix[x+1][y]&&vis[x+1][y] == 0) 15 f(matrix,vis,target,x+1,y); 16 if(y+1 < matrix[0].size()&&target >= matrix[x][y+1]&& vis[x][y+1] == 0) 17 f(matrix,vis,target,x,y+1); 18 } 19 bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) { 20 if(matrix.size() == 0) 21 return ans; 22 vector<vector<int>> vis(matrix.size(),vector<int>(matrix[0].size(),0)); 23 f(matrix,vis,target,0,0); 24 return ans; 25 } 26 };
剑指 Offer 05. 替换空格 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 string replaceSpace(string s) { 4 string ans = ""; 5 for(int i=0;i<s.size();i++){ 6 if(s[i]!=' ') 7 ans+=s[i]; 8 else 9 ans+="%20"; 10 } 11 return ans; 12 } 13 };
剑指 Offer 06. 从尾到头打印链表 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> reversePrint(ListNode* head) { 4 ListNode* pre = nullptr,*cur = head; 5 while(cur){ 6 ListNode *t = cur->next; 7 cur->next = pre; 8 pre = cur; 9 cur = t; 10 } 11 vector<int> ans; 12 while(pre){ 13 ans.push_back(pre->val); 14 pre = pre->next; 15 } 16 return ans; 17 } 18 };
剑指 Offer 07. 重建二叉树 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 TreeNode* f(vector<int>& preorder, vector<int>& inorder,int leftp,int rightp,int lefti,int righti){ 4 if(leftp>rightp||lefti>righti) 5 return nullptr; 6 TreeNode* root = new TreeNode(preorder[leftp]); 7 int mid; 8 for(int i=lefti;i<=righti;i++){ 9 if(inorder[i] == preorder[leftp]){ 10 mid = i; 11 break; 12 } 13 } 14 int leftlen = mid-lefti+1; 15 root->left = f(preorder,inorder,leftp+1,leftp+leftlen-1,lefti,mid-1); 16 root->right = f(preorder,inorder,leftp+leftlen,rightp,mid+1,righti); 17 return root; 18 } 19 TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { 20 return f(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1); 21 22 } 23 };
剑指 Offer 09. 用两个栈实现队列 - 力扣(LeetCode) (leetcode-cn.com)
1 class CQueue { 2 public: 3 CQueue() { 4 5 } 6 stack<int> s1,s2; 7 void appendTail(int value) { 8 s1.push(value); 9 } 10 11 int deleteHead() { 12 if(s2.empty()){ 13 while(!s1.empty()){ 14 s2.push(s1.top()); 15 s1.pop(); 16 } 17 18 } 19 if(s2.empty()) 20 return -1; 21 int head = s2.top(); 22 s2.pop(); 23 return head; 24 } 25 };
剑指 Offer 10- I. 斐波那契数列 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int fib(int n) { 4 long a = 0,b = 1; 5 if(n==0) 6 return a; 7 while(n>=2){ 8 long c = a+b%1000000007; 9 a = b; 10 b = c; 11 n--; 12 } 13 return b%1000000007; 14 } 15 };
剑指 Offer 10- II. 青蛙跳台阶问题 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int numWays(int n) { 4 long a = 1,b = 2; 5 if(n==0||n==1) 6 return a; 7 while(n>2){ 8 long c = a+b%1000000007; 9 a = b; 10 b = c; 11 n--; 12 } 13 return b%1000000007; 14 } 15 };
剑指 Offer 11. 旋转数组的最小数字 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int minArray(vector<int>& numbers) { 4 int l = 0,r = numbers.size()-1; 5 while(l<r){ 6 int mid =(l+r)/2; 7 if(numbers[mid]>numbers[r]){ 8 l = mid+1; 9 }else if(numbers[mid]<numbers[r]){ 10 r = mid;//细节边界 11 }else{ 12 r--; 13 } 14 } 15 return numbers[l]; 16 } 17 };
剑指 Offer 12. 矩阵中的路径 - 力扣(LeetCode) (leetcode-cn.com)
这道题真离谱,多一点点代码都过不了
1 class Solution { 2 public: 3 bool exist(vector<vector<char>>& board, string word) { 4 rows = board.size(); 5 cols = board[0].size(); 6 for(int i = 0; i < rows; i++) { 7 for(int j = 0; j < cols; j++) { 8 if(dfs(board, word, i, j, 0)) return true; 9 } 10 } 11 return false; 12 } 13 private: 14 int rows, cols; 15 bool dfs(vector<vector<char>>& board, string word, int i, int j, int k) { 16 if(i >= rows || i < 0 || j >= cols || j < 0 || board[i][j] != word[k]) return false; 17 if(k == word.size() - 1) return true; 18 board[i][j] = '\0'; 19 bool res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 20 dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1); 21 board[i][j] = word[k]; 22 return res; 23 } 24 };
剑指 Offer 13. 机器人的运动范围 - 力扣(LeetCode) (leetcode-cn.com)
这种题四个方向爆搜,换汤不换药
1 class Solution { 2 public: 3 int ans; 4 int vis[200][200]; 5 void f(int m, int n, int k,int x,int y){ 6 if(x<0||x>=m||y<0||y>=n) 7 return ; 8 int t = 0; 9 int x1 = x,y1 = y;//后面还要用x,y,不能直接修改xy 10 while(x1||y1){ 11 t = t + x1%10 + y1%10; 12 x1/=10,y1/=10; 13 } 14 if(t>k||vis[x][y]) 15 return ; 16 ans++; 17 vis[x][y] = 1; 18 f(m,n,k,x+1,y); 19 f(m,n,k,x,y+1); 20 f(m,n,k,x-1,y); 21 f(m,n,k,x,y-1); 22 } 23 int movingCount(int m, int n, int k) { 24 f(m,n,k,0,0); 25 return ans; 26 } 27 };
剑指 Offer 14- I. 剪绳子 - 力扣(LeetCode) (leetcode-cn.com)
数学问题,多举例,先解决边界问题等特殊情况再找一般规律
1 class Solution { 2 public: 3 int cuttingRope(int n) { 4 if(n<=3){ 5 return n-1; 6 } 7 int ans = 1; 8 while(n){ 9 if(n==4){ 10 ans*=4; 11 break; 12 } 13 if(n==2){ 14 ans*=2; 15 break; 16 } 17 ans*=3; 18 n-=3; 19 20 21 } 22 return ans; 23 } 24 };
剑指 Offer 14- II. 剪绳子 II - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int cuttingRope(int n) { 4 if(n<=3) 5 return n-1; 6 int ans = 1; 7 while(n){ 8 if(n==4){ 9 ans = (((ans+ans)%1000000007+ans)%1000000007+ans)%1000000007; 10 break; 11 } 12 if(n==2){ 13 ans = (ans+ans)%1000000007; 14 break; 15 } 16 ans=((ans+ans)%1000000007+ans)%1000000007; 17 n-=3; 18 } 19 return ans; 20 } 21 };
剑指 Offer 15. 二进制中1的个数 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int hammingWeight(uint32_t n) { 4 int ans = 0; 5 while(n){ 6 ans = ans+n%2; 7 n = n>>1; 8 } 9 return ans; 10 } 11 };
剑指 Offer 16. 数值的整数次方 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution {//1.00000 2147483647 O(n)过不了必定二分! 2 public: 3 double myPow(double x, int n) {//二分,答案是两部分乘积 4 if(n==0) 5 return 1; 6 if(n==1) 7 return x; 8 if(n==-1) 9 return 1/x; 10 double half = myPow(x,n/2); 11 double mod = myPow(x,n%2); 12 return half*half*mod; 13 } 14 };
剑指 Offer 17. 打印从1到最大的n位数 - 力扣(LeetCode) (leetcode-cn.com)
这道题原题大数,返回类型vector<string>。回溯求解,外面一个for循环表示1-n各个位数的答案,回溯里注意长度0&&i==0这种情况continue就行
1 class Solution { 2 public: 3 vector<int> printNumbers(int n) { 4 if(n==0) 5 return {}; 6 int m = 1; 7 while(n){ 8 m*=10; 9 n--; 10 } 11 vector<int> ans; 12 for(int i=1;i<m;i++){ 13 ans.push_back(i); 14 } 15 return ans; 16 } 17 };
剑指 Offer 18. 删除链表的节点 - 力扣(LeetCode) (leetcode-cn.com)
评论说原著给的参数是链表节点不是节点值,给节点可以直接O(1)方法是把下个节点的值赋给当前节点,然后删除下个节点。如果删除节点是末尾节点,那么从头遍历找到前驱节点进行删除。平均复杂度O(1)。末尾节点不能直接赋值nullptr,改变不了原链表。
1 class Solution { 2 public: 3 ListNode* deleteNode(ListNode* head, int val) { 4 if(!head) 5 return head; 6 if(head->val == val) 7 return head->next; 8 ListNode* pre = head; 9 ListNode* cur = head->next; 10 while(cur){ 11 if(cur->val == val){ 12 pre->next = cur->next; 13 } 14 pre = cur; 15 cur = cur->next; 16 } 17 return head; 18 } 19 };
1 class Solution { 2 public: 3 ListNode* deleteNode(ListNode* head, int val) { 4 if(!head) 5 return head; 6 if(head->val == val) 7 return head->next; 8 head->next = deleteNode(head->next,val); 9 return head; 10 } 11 };
剑指 Offer 20. 表示数值的字符串 - 力扣(LeetCode) (leetcode-cn.com)
这题,有限状态机。最近搞webserver项目,里面解析http请求也讲到了有限状态机,还有点懵。
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> exchange(vector<int>& nums) { 4 int j = 0; 5 for(int i=0;i<nums.size();i++){ 6 if(nums[i]%2==1){ 7 swap(nums[j],nums[i]); 8 j++; 9 } 10 } 11 return nums; 12 } 13 };
剑指 Offer 24. 反转链表 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 ListNode* reverseList(ListNode* head) { 4 ListNode* pre = nullptr,*cur = head; 5 while(cur){ 6 ListNode *t = cur->next; 7 cur->next = pre; 8 pre = cur; 9 cur = t; 10 } 11 return pre;//当前cur位空,返回pre 12 } 13 };
剑指 Offer 25. 合并两个排序的链表 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 4 ListNode* head = new ListNode(); 5 ListNode* cur = head; 6 while(l1||l2){ 7 int x = l1==nullptr?INT_MAX:l1->val; 8 int y = l2==nullptr?INT_MAX:l2->val; 9 if(x<y){ 10 cur->next = l1; 11 l1 = l1->next; 12 }else{ 13 cur->next = l2; 14 l2 = l2->next; 15 } 16 cur = cur->next; 17 } 18 return head->next; 19 } 20 };
剑指 Offer 26. 树的子结构 - 力扣(LeetCode) (leetcode-cn.com)
遇事不决暴力解决,越写越明朗
1 class Solution { 2 public: 3 bool f(TreeNode* A,TreeNode* B){ 4 if(B == nullptr) 5 return true; 6 if(A == nullptr) 7 return false; 8 if(A->val!=B->val) 9 return false; 10 return f(A->left,B->left)&&f(A->right,B->right); 11 } 12 bool isSubStructure(TreeNode* A, TreeNode* B) {//B空树返回false 13 if(B == nullptr) 14 return false; 15 if(A == nullptr) 16 return false; 17 if(A->val == B->val){ 18 return f(A,B)||isSubStructure(A->left,B)||isSubStructure(A->right,B); 19 } 20 return isSubStructure(A->left,B)||isSubStructure(A->right,B); 21 } 22 };
剑指 Offer 27. 二叉树的镜像 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution {//注意如果不用临时变量,会有覆盖问题导致节点丢失 2 public: 3 TreeNode* mirrorTree(TreeNode* root) { 4 if(!root) 5 return root; 6 TreeNode *t = root->left; 7 root->left = mirrorTree(root->right); 8 root->right = mirrorTree(t); 9 return root; 10 } 11 };
剑指 Offer 28. 对称的二叉树 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool f(TreeNode* root1,TreeNode* root2){ 4 if(root1==nullptr&&root2==nullptr) 5 return true; 6 if(root1==nullptr||root2==nullptr) 7 return false; 8 if(root1->val!=root2->val) 9 return false; 10 return f(root1->left,root2->right)&&f(root1->right,root2->left); 11 } 12 bool isSymmetric(TreeNode* root) { 13 return f(root,root); 14 } 15 };
剑指 Offer 29. 顺时针打印矩阵 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int>ans; 4 int m,n; 5 void f(vector<vector<int>>& matrix,int x,int y){ 6 if(x>=m||y>=n) 7 return; 8 for(int j=y;j<n;j++){ 9 ans.push_back(matrix[x][j]); 10 } 11 x++; 12 if(x>=m||y>=n) 13 return; 14 for(int i=x;i<m;i++){ 15 ans.push_back(matrix[i][n-1]); 16 } 17 n--; 18 if(x>=m||y>=n) 19 return; 20 for(int j=n-1;j>=y;j--){ 21 ans.push_back(matrix[m-1][j]); 22 } 23 m--; 24 if(x>=m||y>=n) 25 return; 26 for(int i=m-1;i>=x;i--){ 27 ans.push_back(matrix[i][y]); 28 } 29 y++; 30 f(matrix,x,y); 31 } 32 vector<int> spiralOrder(vector<vector<int>>& matrix) { 33 if(matrix.size()==0) 34 return ans; 35 m = matrix.size(); 36 n = matrix[0].size(); 37 f(matrix,0,0); 38 return ans; 39 } 40 };
剑指 Offer 30. 包含min函数的栈 - 力扣(LeetCode) (leetcode-cn.com)
空间换时间,链表维护栈,链表里元素多一个min,记录在此之前的最小值
1 class Node{ 2 public: 3 int data; 4 int min; 5 Node* next; 6 Node(int data,int min,Node* next){ 7 this->data = data; 8 this->min = min; 9 this->next = next; 10 } 11 }; 12 class MinStack { 13 public: 14 Node* head; 15 MinStack() { 16 head = new Node(0,0,nullptr); 17 } 18 19 void push(int x) { 20 int y = head->next?head->next->min:x;//维护最小值 21 y = y<x?y:x; 22 Node *t = new Node(x,y,head->next); 23 head->next = t; 24 } 25 26 void pop() { 27 head->next = head->next->next; 28 } 29 30 int top() { 31 return head->next->data; 32 } 33 34 int min() { 35 return head->next->min; 36 } 37 38 };
剑指 Offer 31. 栈的压入、弹出序列 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool validateStackSequences(vector<int>& pushed, vector<int>& popped) { 4 stack<int>st; 5 int j=0; 6 for(int i=0;i<pushed.size();i++){ 7 st.push(pushed[i]); 8 while(!st.empty()&&st.top() == popped[j]){ 9 j++; 10 st.pop(); 11 } 12 } 13 if(j==pushed.size()&&st.empty()) 14 return true; 15 else 16 return false; 17 } 18 };
剑指 Offer 32 - II. 从上到下打印二叉树 II - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<vector<int>> levelOrder(TreeNode* root) { 4 vector<vector<int>> result; 5 if(root==nullptr) 6 return result; 7 queue<TreeNode*>que; 8 que.push(root); 9 while(!que.empty()){ 10 int n = que.size(); 11 vector<int>path; 12 for(int i=0;i<n;i++){ 13 TreeNode* t = que.front(); 14 que.pop(); 15 if(t){ 16 path.push_back(t->val); 17 if(t->left) 18 que.push(t->left); 19 if(t->right) 20 que.push(t->right); 21 } 22 23 } 24 result.push_back(path); 25 } 26 return result; 27 } 28 };
剑指 Offer 32 - III. 从上到下打印二叉树 III - 力扣(LeetCode) (leetcode-cn.com)
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<vector<int>> levelOrder(TreeNode* root) { 13 if(root == nullptr) 14 return {}; 15 vector<vector<int>> result; 16 queue<TreeNode*>que; 17 que.push(root); 18 int k = 1; 19 while(!que.empty()){ 20 vector<int>path; 21 int n = que.size(); 22 while(n--){ 23 TreeNode* t = que.front(); 24 que.pop(); 25 path.push_back(t->val); 26 if(t->left) 27 que.push(t->left); 28 if(t->right) 29 que.push(t->right); 30 } 31 if(k%2==0){ 32 reverse(path.begin(),path.end()); 33 } 34 result.push_back(path); 35 k++; 36 } 37 return result; 38 } 39 };
剑指 Offer 33. 二叉搜索树的后序遍历序列 - 力扣(LeetCode) (leetcode-cn.com)
这道题时间复杂度没看懂
1 class Solution { 2 public: 3 bool f(vector<int>& postorder,int l,int r){ 4 if(l>=r) 5 return true; 6 int i = l; 7 while(postorder[i]<postorder[r]){ 8 i++; 9 } 10 int mid = i; 11 while(postorder[i]>postorder[r]){ 12 i++; 13 } 14 return i==r&&f(postorder,l,mid-1)&&f(postorder,mid,r-1); 15 } 16 bool verifyPostorder(vector<int>& postorder) { 17 return f(postorder,0,postorder.size()-1); 18 } 19 };
剑指 Offer 34. 二叉树中和为某一值的路径 - 力扣(LeetCode) (leetcode-cn.com)
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 * }; 11 */ 12 class Solution { 13 public: 14 vector<int>path; 15 vector<vector<int>> result; 16 void f(TreeNode* root,int target,int num){ 17 if(!root) 18 return ; 19 num+=root->val; 20 path.push_back(root->val); 21 if(root->left==nullptr&&root->right==nullptr){ 22 if(num==target){ 23 result.push_back(path); 24 } 25 } 26 f(root->left,target,num); 27 f(root->right,target,num); 28 path.pop_back(); 29 } 30 vector<vector<int>> pathSum(TreeNode* root, int target) { 31 f(root,target,0); 32 return result; 33 } 34 };
剑指 Offer 35. 复杂链表的复制 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 Node* copyRandomList(Node* head) { 4 if(head == nullptr) 5 return nullptr; 6 Node* cur = head; 7 while(cur){ 8 Node* t = new Node(cur->val); 9 t->next = cur->next; 10 cur->next = t; 11 cur = cur->next->next; 12 } 13 cur = head; 14 while(cur){ 15 cur->next->random = cur->random?cur->random->next:nullptr;//为啥是random->next,因为random要只向新生成的节点 16 cur = cur->next->next; 17 } 18 cur = head; 19 Node *ans = head->next; 20 Node *copy = head->next; 21 while(cur){ 22 cur->next = cur->next->next; 23 cur = cur->next; 24 if(ans->next){ 25 ans->next = ans->next->next; 26 ans = ans->next; 27 } 28 } 29 return copy; 30 } 31 };class Solution { 32 public: 33 Node* copyRandomList(Node* head) { 34 if(head == nullptr) 35 return nullptr; 36 Node* cur = head; 37 while(cur){ 38 Node* t = new Node(cur->val); 39 t->next = cur->next; 40 cur->next = t; 41 cur = cur->next->next; 42 } 43 cur = head; 44 while(cur){ 45 cur->next->random = cur->random?cur->random->next:nullptr;//为啥是random->next,因为random要只向新生成的节点 46 cur = cur->next->next; 47 } 48 cur = head; 49 Node *ans = head->next; 50 Node *copy = head->next; 51 while(cur){ 52 cur->next = cur->next->next; 53 cur = cur->next; 54 if(ans->next){ 55 ans->next = ans->next->next; 56 ans = ans->next; 57 } 58 } 59 return copy; 60 } 61 };
剑指 Offer 36. 二叉搜索树与双向链表 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 Node *head,*pre; 4 Node* treeToDoublyList(Node* root) { 5 if(root == nullptr) 6 return root; 7 dfs(root); 8 head->left = pre; 9 pre->right = head; 10 return head; 11 } 12 void dfs(Node* cur){ 13 if(cur == nullptr) 14 return ; 15 dfs(cur->left); 16 if(pre == nullptr){ 17 head = cur; 18 cur->left = nullptr; 19 }else{ 20 cur->left = pre; 21 pre->right = cur; 22 } 23 pre = cur; 24 dfs(cur->right); 25 } 26 };
剑指 Offer 38. 字符串的排列 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<string> result; 4 string path; 5 unordered_set<string> set; 6 bool vis[10]; 7 void f(string s,int index){ 8 if(path.size()==s.size()-1){ 9 path.push_back(s[index]); 10 if(set.count(path) == 0){ 11 result.push_back(path); 12 set.insert(path); 13 } 14 path.pop_back(); 15 return ; 16 } 17 vis[index] = 1; 18 path.push_back(s[index]); 19 for(int i=0;i<s.size();i++){ 20 if(vis[i] == false){ 21 f(s,i); 22 } 23 24 } 25 vis[index] = 0; 26 path.pop_back(); 27 } 28 vector<string> permutation(string s) { 29 for(int i=0;i<s.size();i++){ 30 f(s,i); 31 } 32 return result; 33 } 34 };
剑指 Offer 39. 数组中出现次数超过一半的数字 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int majorityElement(vector<int>& nums) { 4 int n = nums.size(); 5 unordered_map<int,int> map; 6 for(int i=0;i<n;i++){ 7 map[nums[i]]++; 8 cout<<map[nums[i]]; 9 if(map[nums[i]]>n/2) 10 return nums[i]; 11 } 12 return 0; 13 } 14 };
剑指 Offer 40. 最小的k个数 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 void qsort(vector<int>& arr,int l,int r){ 4 if(l>=r) 5 return ; 6 int cmp = l; 7 int j = l; 8 for(int i=l+1;i<=r;i++){ 9 if(arr[i]<arr[cmp]){ 10 swap(arr[i],arr[++j]); 11 } 12 } 13 swap(arr[cmp],arr[j]); 14 qsort(arr,l,j-1); 15 qsort(arr,j+1,r); 16 } 17 vector<int> getLeastNumbers(vector<int>& arr, int k) { 18 qsort(arr,0,arr.size()-1); 19 vector<int> ans; 20 for(int i=0;i<k;i++) 21 ans.push_back(arr[i]); 22 return ans; 23 } 24 };
剑指 Offer 42. 连续子数组的最大和 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int maxSubArray(vector<int>& nums) { 4 int ans = nums[0],sum = 0; 5 for(int i=0;i<nums.size();i++){ 6 sum+=nums[i]; 7 ans = max(ans,sum); 8 sum = max(sum,0); 9 } 10 return ans; 11 } 12 };
剑指 Offer 44. 数字序列中某一位的数字 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int findNthDigit(int n) { 4 if(n<10) 5 return n; 6 long dp[20] = {1,10,190,2890,38890,488890,5888890,68888890,788888890,8888888890,98888888890};//190,2位数字最大是99,0~99加起来位数是190,10+90*2 7 int sum = 0,x = n; 8 for(int i=0;i<20;i++){//求出几位数,sum 9 if(dp[i]>n){ 10 sum = i; 11 break; 12 } 13 } 14 int j = sum; 15 int minn = 0; 16 while(--j){//比如三位数,那么找到两位数最大值99 17 minn = minn*10+9; 18 } 19 int count = (n-dp[sum-1]+1)%sum; //dp数组表示的是有多少个数,n是从0开始的,所以0~n有n+1个数 20 int number = minn+(n-dp[sum-1]+1)/sum; 21 if(count == 0){ 22 string s = to_string(number); 23 return s[s.size()-1]-'0'; 24 }else{ 25 string s = to_string(number+1); 26 return s[count-1]-'0';//count表示第几个数,对应下标要减一 27 } 28 return 0; 29 } 30 };
剑指 Offer 45. 把数组排成最小的数 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 static bool cmp(string x,string y){ 4 return x+y<y+x; 5 } 6 string minNumber(vector<int>& nums) { 7 vector<string>s; 8 sort(nums.begin(),nums.end()); 9 for(int i=0;i<nums.size();i++){ 10 s.push_back(to_string(nums[i])); 11 } 12 sort(s.begin(),s.end(),cmp); 13 string ans = ""; 14 for(int i=0;i<nums.size();i++){ 15 ans+=s[i]; 16 } 17 return ans; 18 } 19 };
剑指 Offer 46. 把数字翻译成字符串 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int result; 4 void f(string s,int index){ 5 if(index>=s.size()){ 6 result++; 7 return ; 8 } 9 f(s,index+1); 10 if(index+1<s.size()&&s[index]!='0'&&s.substr(index,2)<="25")//11,506 11 f(s,index+2); 12 } 13 int translateNum(int num) { 14 string s = to_string(num); 15 f(s,0); 16 return result; 17 } 18 };
剑指 Offer 47. 礼物的最大价值 - 力扣(LeetCode) (leetcode-cn.com)
dp,以前这种二维矩阵都是dfs爆搜,现在学会dp了。
1 class Solution { 2 public: 3 int maxValue(vector<vector<int>>& grid) { 4 for(int i=0;i<grid.size();i++){ 5 for(int j=0;j<grid[0].size();j++){ 6 if(i>0&&j>0){ 7 grid[i][j] = max(grid[i-1][j],grid[i][j-1])+grid[i][j]; 8 }else if(i>0){ 9 grid[i][j] += grid[i-1][j]; 10 }else if(j>0){ 11 grid[i][j] += grid[i][j-1]; 12 } 13 } 14 } 15 return grid[grid.size()-1][grid[0].size()-1]; 16 } 17 };
剑指 Offer 48. 最长不含重复字符的子字符串 - 力扣(LeetCode) (leetcode-cn.com)
双指针加map
1 class Solution { 2 public: 3 int lengthOfLongestSubstring(string s) { 4 int n = s.size(); 5 if(n==0) 6 return 0; 7 vector<int> dp(n,1); 8 unordered_map<char,int> map; 9 dp[0] = 1; 10 int ans = 1; 11 map[s[0]] = 0; 12 int j = 0;//合法子串的起始边界 13 for(int i=1;i<n;i++){ 14 if(map.count(s[i]) == 0){ 15 dp[i] = dp[i-1]+1; 16 }else{ 17 j = max(j,map[s[i]]+1); 18 cout<<"i="<<i<<" j="<<j<<endl; 19 dp[i] = i - j + 1; 20 } 21 map[s[i]] = i; 22 ans = max(ans,dp[i]); 23 } 24 return ans; 25 } 26 };
剑指 Offer 49. 丑数 - 力扣(LeetCode) (leetcode-cn.com)
想着除法判断丑数结果发现不行,原来是在已经是 丑数的基础上做有效乘法
1 class Solution { 2 public: 3 int nthUglyNumber(int n) { 4 vector<int> dp(n + 1); 5 dp[1] = 1; 6 int p2 = 1, p3 = 1, p5 = 1; 7 for (int i = 2; i <= n; i++) { 8 int num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5; 9 dp[i] = min(min(num2, num3), num5); 10 if (dp[i] == num2) { 11 p2++; 12 } 13 if (dp[i] == num3) { 14 p3++; 15 } 16 if (dp[i] == num5) { 17 p5++; 18 } 19 } 20 return dp[n]; 21 } 22 };
剑指 Offer 50. 第一个只出现一次的字符 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 char firstUniqChar(string s) { 4 int a[26] = {0}; 5 for(int i=0;i<s.size();i++){ 6 a[s[i]-'a']++; 7 } 8 for(int i=0;i<s.size();i++){ 9 if(a[s[i]-'a']==1) 10 return s[i]; 11 } 12 return ' '; 13 } 14 };
剑指 Offer 51. 数组中的逆序对 - 力扣(LeetCode) (leetcode-cn.com)
官方题解初看没看懂,按思路应该是和下面代码一样,左边数大于右边数,右边数存入tmp数组,ans+=mid-i+1。意思是对于nums[j],左数组i之后mid之前这部分,都与之构成逆序对。
1 class Solution { 2 public: 3 /* 合并有序数组 */ 4 int merge(vector<int>& nums, int left, int right) { 5 int tmp[50050] = {0}; 6 int idx = 0; 7 int mid = (left+right)/2; 8 int i = left; 9 int j = mid + 1; 10 int ans = 0; 11 while (i <= mid && j <= right) { 12 if (nums[i] > nums[j]) { 13 ans += mid - i + 1; /* 统计逆序对 当前nums[i]往后的都比nums[j]大*/ 14 tmp[idx++] = nums[j++]; 15 } else { 16 tmp[idx++] = nums[i++]; 17 } 18 } 19 20 /* 处理剩余数组 */ 21 while (i <= mid) { 22 tmp[idx++] = nums[i++]; 23 } 24 while (j <= right) { 25 tmp[idx++] = nums[j++]; 26 } 27 28 /* 写到原数组中 */ 29 for (int k = 0; k < idx; k++) { 30 nums[left + k] = tmp[k]; 31 } 32 return ans; 33 } 34 35 int mergeSort(vector<int>& nums, int l, int r) { 36 if (l >= r) { 37 return 0; 38 } 39 int m = (l+r)/2; 40 int revCnt = mergeSort(nums, l, m) + mergeSort(nums, m + 1, r); 41 return revCnt + merge(nums, l ,r); 42 } 43 44 int reversePairs(vector<int>& nums) { 45 int n = nums.size(); 46 return mergeSort(nums, 0, n - 1); 47 } 48 };
剑指 Offer 52. 两个链表的第一个公共节点 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 4 ListNode *HA = headA,*HB = headB; 5 while(headA!=headB){ 6 headA = headA==nullptr?HB:headA->next; 7 headB = headB==nullptr?HA:headB->next; 8 } 9 return headA; 10 } 11 };
剑指 Offer 53 - I. 在排序数组中查找数字 I - 力扣(LeetCode) (leetcode-cn.com)
二分两次找左右边界
1 class Solution { 2 public: 3 int search(vector<int>& nums, int target) {//两次二分,找边界 4 int n = nums.size(); 5 if(n == 0) 6 return 0; 7 int l = 0,r = n-1; 8 int right = -1;//没找到的保证答案为0 9 while(l<=r){ 10 int mid = (l+r)/2; 11 if(nums[mid] == target){ 12 l = mid+1; 13 right = mid; 14 } 15 else if(nums[mid]<target){ 16 l = mid+1; 17 18 }else{ 19 r = mid-1; 20 } 21 } 22 23 l = 0,r = n-1; 24 int left = 0; 25 while(l<=r){ 26 int mid = (l+r)/2; 27 if(nums[mid] == target){ 28 r = mid-1; 29 left = mid; 30 } 31 else if(nums[mid]>target){ 32 r = mid-1; 33 }else{ 34 l = mid+1; 35 } 36 } 37 // cout<<left<<right<<endl; 38 return right-left+1; 39 } 40 };
二分一次,往左右延申
1 class Solution { 2 public: 3 int search(vector<int>& nums, int target) { 4 int n = nums.size(); 5 if(n == 0) 6 return 0; 7 int l = 0,r = n-1; 8 while(l<=r){ 9 int mid = (l+r)/2; 10 if(nums[mid] == target) 11 break; 12 else if(nums[mid]<target){ 13 l = mid+1; 14 }else{ 15 r = mid-1; 16 } 17 } 18 int ans = 0; 19 int mid1 = (l+r)/2,mid2 = (l+r)/2+1; 20 while(mid1>=0&&nums[mid1] == target){ 21 ans++; 22 mid1--; 23 } 24 while(mid2<n&&nums[mid2] == target){ 25 ans++; 26 mid2++; 27 } 28 return ans; 29 } 30 };
剑指 Offer 53 - II. 0~n-1中缺失的数字 - 力扣(LeetCode) (leetcode-cn.com)
特点,i = nums[i]
1 class Solution { 2 public: 3 int missingNumber(vector<int>& nums) { 4 int left = 0; 5 int right = nums.size() - 1; 6 while(left <= right) { 7 int mid = (left + right) / 2; 8 /* 如果相等说明 left 到 mid 中间肯定不少元素 所以往右边二分查找 */ 9 if(nums[mid] == mid) left = mid + 1; 10 else right = mid - 1; 11 } 12 return left; 13 } 14 };
剑指 Offer 54. 二叉搜索树的第k大节点 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int ans; 4 int num; 5 void f(TreeNode* root){ 6 if(root == nullptr) 7 return ; 8 f(root->right); 9 if(num == 1){ 10 ans = root->val; 11 num--; 12 return ; 13 } 14 num--; 15 f(root->left); 16 17 18 } 19 int kthLargest(TreeNode* root, int k) { 20 num = k; 21 f(root); 22 return ans; 23 } 24 };
剑指 Offer 55 - I. 二叉树的深度 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int f(TreeNode* root,int depth){ 4 if(root == nullptr) 5 return depth; 6 return max(f(root->left,depth),f(root->right,depth))+1; 7 } 8 int maxDepth(TreeNode* root) { 9 return f(root,0); 10 } 11 };
剑指 Offer 56 - I. 数组中数字出现的次数 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> singleNumbers(vector<int>& nums) { 4 int ret = 0; 5 for (int x : nums) 6 ret ^= x; 7 int div = 1; 8 while ((div & ret) == 0) 9 div <<= 1; 10 int a = 0, b = 0; 11 for (int x : nums) 12 if (div & x) 13 a ^= x; 14 else 15 b ^= x; 16 return vector<int>{a, b}; 17 } 18 };
剑指 Offer 57. 和为s的两个数字 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> twoSum(vector<int>& nums, int target) { 4 for(int i=0,j=nums.size()-1;i<nums.size()&&j>=i;){ 5 if(nums[i]+nums[j] == target){ 6 return {nums[i],nums[j]}; 7 }else if(nums[i]<target-nums[j]){ 8 i++; 9 }else{ 10 j--; 11 } 12 } 13 return {}; 14 } 15 };
剑指 Offer 57 - II. 和为s的连续正数序列 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<vector<int>> findContinuousSequence(int target) { 4 vector<vector<int>> result; 5 for(int i=1,j=2;i<j;){ 6 if((i+j)*(j-i+1)/2 == target){ 7 vector<int> path; 8 for(int x=i;x<=j;x++) 9 path.push_back(x); 10 result.push_back(path); 11 //要执行i,j变化不然会超时 12 i++,j++; 13 }else if((i+j)*(j-i+1)/2 < target){ 14 j++; 15 }else{ 16 i++; 17 } 18 } 19 return result; 20 } 21 };
剑指 Offer 58 - I. 翻转单词顺序 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 string reverseWords(string s) 4 { 5 string res; 6 for(int j = s.size() - 1; j >= 0; --j) 7 { 8 if(s[j] == ' ') 9 continue; 10 11 int i = j; 12 while(i >= 0 && s[i] != ' ') i--; 13 res.append(s.substr(i + 1, j - i)); 14 res.append(" "); 15 j = i; 16 } 17 18 if(!res.empty()) res.pop_back(); 19 return res; 20 } 21 };
剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 string reverseLeftWords(string s, int n) { 4 string ans = s.substr(n,s.size()-n); 5 ans +=s.substr(0,n); 6 return ans; 7 } 8 };
剑指 Offer 59 - I. 滑动窗口的最大值 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<int> maxSlidingWindow(vector<int>& nums, int k) {//7 2 4 窗口过了,怎么弹出那个不在窗口的最大元素。以为队列里要存pair结构体,其实存i就行了,知i即nums[i] 4 deque<int> que; 5 vector<int> ans; 6 for(int i=0;i<nums.size();i++){ 7 if(que.empty()){ 8 que.push_back(i); 9 }else if(nums[que.back()]<=nums[i]){ 10 while(!que.empty()&&nums[que.back()]<=nums[i]) 11 que.pop_back(); 12 que.push_back(i); 13 }else{ 14 que.push_back(i); 15 } 16 if(i>=k){ 17 if(que.front()<=i-k) 18 que.pop_front(); 19 } 20 if(i>=k-1&&!que.empty()){ 21 ans.push_back(nums[que.front()]); 22 } 23 24 } 25 26 return ans; 27 } 28 };
剑指 Offer 59 - II. 队列的最大值 - 力扣(LeetCode) (leetcode-cn.com)
1 class MaxQueue { 2 public: 3 MaxQueue() { 4 } 5 queue<int> q; 6 deque<int> d; 7 int max_value() { 8 if (d.empty()) 9 return -1; 10 return d.front(); 11 } 12 13 void push_back(int value) { 14 while (!d.empty() && d.back() < value) { 15 d.pop_back(); 16 } 17 d.push_back(value); 18 q.push(value); 19 } 20 21 int pop_front() { 22 if (q.empty()) 23 return -1; 24 int ans = q.front(); 25 if (ans == d.front()) { 26 d.pop_front(); 27 } 28 q.pop(); 29 return ans; 30 } 31 };
剑指 Offer 60. n个骰子的点数 - 力扣(LeetCode) (leetcode-cn.com)
这个题,一是递归会超时,二是数据处理上,最后除以一个分母就行,初始化第一个骰子情况6个1
1 class Solution { 2 public: 3 vector<double> twoSum(int n) { 4 int dp[15][70]; 5 memset(dp, 0, sizeof(dp)); 6 for (int i = 1; i <= 6; i ++) { 7 dp[1][i] = 1; 8 } 9 for (int i = 2; i <= n; i ++) { 10 for (int j = i; j <= 6*i; j ++) { 11 for (int cur = 1; cur <= 6; cur ++) { 12 if (j - cur <= 0) { 13 break; 14 } 15 dp[i][j] += dp[i-1][j-cur]; 16 } 17 } 18 } 19 int all = pow(6, n); 20 vector<double> ret; 21 for (int i = n; i <= 6 * n; i ++) { 22 ret.push_back(dp[n][i] * 1.0 / all); 23 } 24 return ret; 25 } 26 };
剑指 Offer 61. 扑克牌中的顺子 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool isStraight(vector<int>& nums) { 4 sort(nums.begin(),nums.end()); 5 int all = 0;//表示大小王 6 int sub = 0; 7 for(int i = 0;i<nums.size();i++){//还有01123这情况 8 if(nums[i]==0) 9 all++; 10 else if(i>0&&nums[i-1]!=0&&nums[i]!=nums[i-1]) 11 sub = sub+nums[i]-nums[i-1]-1; 12 else if(i>0&&nums[i]==nums[i-1]){ 13 return false; 14 } 15 } 16 if(all>=sub) 17 return true; 18 else 19 return false; 20 } 21 };
剑指 Offer 63. 股票的最大利润 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int maxProfit(vector<int>& prices) { 4 int n =prices.size(); 5 if(n == 0) 6 return 0; 7 int mn = prices[0]; 8 int ans = 0; 9 for(int i=1;i<n;i++){ 10 ans = max(ans,prices[i]-mn); 11 mn = min(mn,prices[i]); 12 } 13 return ans; 14 } 15 };
剑指 Offer 68 - II. 二叉树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)
左右子树都不空时返回根节点,否则返回左右子树不空那个
1 class Solution { 2 public: 3 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 4 if(root == nullptr) 5 return nullptr; 6 if(root == p||root == q) 7 return root; 8 root->left = lowestCommonAncestor(root->left,p,q); 9 root->right = lowestCommonAncestor(root->right,p,q); 10 if(root->left&&root->right) 11 return root; 12 else 13 root = root->left?root->left:root->right; 14 return root; 15 } 16 };