剑指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 };
View Code

 

剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code
 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 };
View Code 递归

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

二分一次,往左右延申

 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

  剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 }; 
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 剑指 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 };
View Code

 

posted @ 2022-03-13 13:14  剩下的交给时间就好  阅读(127)  评论(0编辑  收藏  举报