剑指offer刷题

文章目录

  • 剑指offer刷题
    • 03 [数组中重复的数字]
    • 04 [二维数组中的查找]
    • 05 [替换空格]
    • 06 [从尾到头打印链表]
    • 07 [重建二叉树]
    • 09 [用两个栈实现队列]
    • 10-I [斐波那契数列]
    • 10-II [青蛙跳台阶问题]
    • 11 [旋转数组的最小数字]
    • 12 [矩阵中的路径]
    • 13 [机器人的运动范围]
    • 14-I [剪绳子]
    • 14-II [剪绳子 II]
    • 15 [二进制中 1 的个数]
    • 16 [数值的整数次方]
    • 17 [打印从 1 到最大的 n 位数] 数学
    • 18 [删除链表的节点] 链表
    • 19 [正则表达式匹配]
    • 20 [表示数值的字符串]
    • 21 [调整数组顺序使奇数位于偶数前面]
    • 22 [链表中倒数第 k 个节点]
    • 24 [反转链表]
    • 25 [合并两个排序的链表]
    • 26 [树的子结构]
    • 27 [二叉树的镜像]
    • 28 [对称的二叉树]
    • 29 [顺时针打印矩阵]
    • 30 [包含 min 函数的栈]
    • 31 [栈的压入、弹出序列]
    • 32-I [从上到下打印二叉树]
    • 32-II [从上到下打印二叉树 II]
    • 32-III [从上到下打印二叉树 III]
    • 33 [二叉搜索树的后序遍历序列]
    • 34 [二叉树中和为某一值的路径]
    • 35 [复杂链表的复制]
    • 36 [二叉搜索树与双向链表]
    • 37 [序列化二叉树]
    • 38 [字符串的排列]
    • 39 [数组中出现次数超过一半的数字]
    • 40 [最小的 k 个数]
    • 41 [数据流中的中位数]
    • 42 [连续子数组的最大和]
    • 43 [1 ~ n 整数中 1 出现的次数]
    • 44 [数字序列中某一位的数字]
    • 45 [把数组排成最小的数] 排序
    • 46 [把数字翻译成字符串]
    • 47 [礼物的最大价值] 动态规划
    • 48 [最长不含重复字符的子字符串]
    • 49 [丑数]
    • 50 [第一个只出现一次的字符]
    • 51 [数组中的逆序对]
    • 52 [两个链表的第一个公共节点] 链表
    • 53-I [在排序数组中查找数字 I]
    • 53-II [0 ~ n-1 中缺失的数字]
    • 54 [二叉搜索树的第 k 大节点]
    • 55-I [二叉树的深度]
    • 55-II [平衡二叉树]
    • 56-I [数组中数字出现的次数]
    • 56-II [数组中数字出现的次数 II]
    • 57 [和为 s 的两个数字]
    • 57-II [和为 s 的连续正数序列]
    • 58-I [翻转单词顺序]
    • 58-II [左旋转字符串]
    • 59-I [滑动窗口的最大值]
    • 59-II [队列的最大值]
    • 60 [n 个骰子的点数]
    • 61 [扑克牌中的顺子]
    • 62 [圆圈中最后剩下的数字]
    • 63 [股票的最大利润]
    • 64 [求 1+2+…+n]
    • 65 [不用加减乘除做加法]
    • 66 [构建乘积数组]
    • 67 [把字符串转换成整数]
    • 68-I [二叉搜索树的最近公共祖先]
    • 68-II [二叉树的最近公共祖先]
  • 补充题
    • N皇后
    • 快速排序
    • 486.预测赢家

03 [数组中重复的数字]

class Solution {
public:int findRepeatNumber(vector<int>& nums) {sort(nums.begin(),nums.end());for(int i=0;i<nums.size();i++){if(nums[i+1]==nums[i]){//cout<<nums[i]<<endl;//break;return nums[i];}}return 0;}
};

04 [二维数组中的查找]

class Solution {
public:bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {if(matrix.empty()) return false;if(matrix[0].empty()) return false;int m = matrix.size();int n = matrix[0].size();for(int i=0;i<m;i++){if(matrix[i][0]<=target&&matrix[i][n-1]>=target){for(int j=0;j<n;j++){if(matrix[i][j]==target)return true;}}}return false;}
};

05 [替换空格]

class Solution {
public:string replaceSpace(string s) {vector<int> place;for(int i=0;i<s.size();i++){if(s[i] == ' '){place.push_back(i);}}for(auto it=place.rbegin();it!=place.rend();it++){int i = *it;s[i] = '%';s.insert(i+1,"20");}return s;}
};

insert 是在 pos 处前插。

06 [从尾到头打印链表]

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:vector<int> reversePrint(ListNode* head) {int count = 0;auto tmp = head;while(tmp!=NULL){count++;tmp = tmp->next;}vector<int> result(count,0);tmp = head;while(tmp!=NULL){result[--count] = tmp->val;tmp = tmp->next;}return result;}
};

07 [重建二叉树]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/TreeNode* recursion(vector<int>& preorder,int p1,int p2,vector<int>& inorder,int q1,int q2){if(p1>p2||q1>q2) return NULL;TreeNode* newNode = new TreeNode(preorder[p1]);int leftTreeLen;for(int i=q1;i<=q2;i++){if(preorder[p1] == inorder[i]){leftTreeLen = i-q1;break;}}//递归左子树TreeNode* leftNode = recursion(preorder, p1+1, p1+leftTreeLen,inorder, q1, q1+leftTreeLen-1);newNode->left = leftNode;//递归右子树TreeNode* rightNode = recursion(preorder, p1+leftTreeLen+1, p2,inorder, q1+leftTreeLen+1, q2);newNode->right = rightNode;return newNode;}
class Solution {public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {TreeNode* root;root = recursion(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);return root;}
};

想把树串起来的题,递归时可以把 root 节点返回到上一层。

09 [用两个栈实现队列]

class CQueue {
public:stack<int> s1,s2;CQueue() {}void appendTail(int value) {s1.push(value);}int deleteHead() {if(s2.empty()){if(s1.empty()) return -1;while(!s1.empty()){s2.push(s1.top());s1.pop();}}int tmp = s2.top();s2.pop();return tmp;}
};/*** Your CQueue object will be instantiated and called as such:* CQueue* obj = new CQueue();* obj->appendTail(value);* int param_2 = obj->deleteHead();*/

10-I [斐波那契数列]

class Solution {public:int fib(int n) {int f0 = 0;int f1 = 1;int tmp;if(n==0) return f0;    for(int i=0;i<n-1;i++){//cout<<f1<<endl;tmp = (f0+f1)%1000000007;f0 = f1;f1 = tmp;}//cout<<f1<<endl;return f1;}
};

主要审题要认真,取模要注意。

10-II [青蛙跳台阶问题]

class Solution {public:int numWays(int n) {if(n<=1) return 1;int a1 = 1;int a2 = 2;int a;for(int i=0;i<n-2;i++){a = (a1+a2)%1000000007;a1=a2;a2 = a;}return a2;}
};

11 [旋转数组的最小数字]

class Solution {public:int minArray(vector<int>& numbers) {int size =  numbers.size();for(int i=0;i<size-1;i++){if(numbers[i+1]<numbers[i]){return numbers[i+1];}}return numbers[0];}
};

12 [矩阵中的路径]

class Solution {int iMax,jMax;int size;vector<vector<bool>> b;vector<vector<char>> board1;string word1;
public:bool recursion(int i,int j,int pos){//cout<<"i=="<<i<<"j="<<j<<"pos="<<pos<<"size="<<size<<endl;if(pos==size-1) return true;if(i+1<iMax&&b[i+1][j]&&board1[i+1][j]==word1[pos+1]){b[i+1][j] = false;if(recursion(i+1,j,pos+1)) return true;b[i+1][j] = true;}if(j+1<jMax&&b[i][j+1]&&board1[i][j+1]==word1[pos+1]){//cout<<"position="<<pos<<endl;b[i][j+1] = false;if(recursion(i,j+1,pos+1)) return true;b[i][j+1] = true;}if(i-1>-1&&b[i-1][j]&&board1[i-1][j]==word1[pos+1]){b[i-1][j] = false;if(recursion(i-1,j,pos+1)) return true;b[i-1][j] = true;}if(j-1>-1&&b[i][j-1]&&board1[i][j-1]==word1[pos+1]){//cout<<"hahaha"<<endl;//cout<<"ij_1b"<<i<<j-1<<" "<<b[i][j-1]<<endl;b[i][j-1] = false;if(recursion(i,j-1,pos+1)) return true;b[i][j-1] = true;}return false;}bool exist(vector<vector<char>>& board, string word) {//cout<<"to here"<<endl;iMax = board.size();jMax = board[0].size();//cout<<"iMax="<<iMax<<"jMax"<<jMax<<endl;vector<bool> tmp(jMax,true);//cout<<"to here"<<endl;b.resize(iMax,tmp);board1 = board;word1 = word;size = word.size();for(int i=0;i<iMax;i++){for(int j=0;j<jMax;j++){if(board[i][j]!=word[0]) continue;b[i][j] = false;//cout<<"ij="<<i<<" "<<j<<endl;if(recursion(i,j,0)) return true;b[i][j] = true;}}return false;}
};

13 [机器人的运动范围]

class Solution {int  result;int digitSum(int i,int j){int sum = 0;while(1){ sum = sum+i%10;if(i/10==0) break;i = i/10;    }while(1){ sum = sum+j%10;if(j/10==0) break;j = j/10;    }return sum;}int recursion(int i,int j,int m,int n,vector<vector<bool>> &vis){if(i+1<m&&j<n&&vis[i+1][j]){result++;vis[i+1][j] = false;recursion(i+1,j,m,n,vis);}if(i<m&&j+1<n&&vis[i][j+1]){vis[i][j+1] = false;result++;recursion(i,j+1,m,n,vis);}return 0; }
public:int movingCount(int m, int n, int k) {vector<vector<bool>> vis(m,vector<bool>(n,true));result = 1;for(int i=0;i<m;i++){for(int j=0;j<n;j++){if(digitSum(i,j)>k){vis[i][j] = false;}}}recursion(0,0,m,n,vis);return result;}
};

记住要找一个矩阵记录已经走过的地方。

14-I [剪绳子]

class Solution {
public:int cuttingRope(int n) {vector<int> dp(n+1);dp[2] = 1; for(int i=3;i<n+1;i++){for(int j=1;j<=i-j;j++){//cout<<i<<endl;//cout<<j<<endl;dp[i] = max(dp[i],j*dp[i-j]);dp[i] = max(dp[i],j*(i-j));}}return dp[n];}
};

学会用简单列举法来找动态规划的规律。

14-II [剪绳子 II]

class Solution {int mypow(int a,int n,int base){long int tmp = base;for(int i=0;i<n;i++){tmp = tmp*a;tmp = tmp%1000000007;}return tmp;}
public:int cuttingRope(int n) {if(n==2) return 1;if(n==3) return 2;int num = ceil(n/3.0);int rem = n%3;int r;if(rem==0){r = (mypow(3,num,1));}else if(rem==1){r = mypow(3,num-2,4);}else{r = mypow(3,num-1,2);}return r;}
};

割绳子的题目总是尽可能割成长度为 3 的比较好。不得已的情况下,尽可能地割成等长的。
INT_MAX = 2147483647(十位数)
INT_MIN = -2147483648(十位数)
所以:int -2147483648~2147483647
int 不够放的 long int 一般够了。

15 [二进制中 1 的个数]

class Solution {public:int hammingWeight(uint32_t n) {int count = 0;int rem;while(1){rem = n%2;if(rem==1){count++;}n = n/2;if(n==0) break;}return count;}
};

16 [数值的整数次方]

class Solution {public:double myPow(double x, int n) {if(x==1) return x;double r = 1;int k=n>0?n:-n;for(int i=0;i<k;i++){r = r*x;}cout<<r<<endl;if(n<0){r = 1.0/r;}cout<<r<<endl;return r;}
};

超时版本。

class Solution {public:double myPow(double x, int n) {if(x==1) return 1;if(x == 0) return 0;double res = 1;long int k = (long int)(n);if(n < 0){x = 1/x;k = -k;}//cout<<k<<" "<<x<<endl;while(k!=0){if(k%2){res*=x;}x*=x;k>>=1;}return res;}
};

把 x 变成 x^2 的处理思路,如果 n 是奇数,先提一个给 rem。

17 [打印从 1 到最大的 n 位数] 数学

class Solution {public:vector<int> printNumbers(int n) {int M = pow(10,n)-1;vector<int> res(M);for(int i=1;i<=M;i++){res[i-1] = i;}return res;}
};

18 [删除链表的节点] 链表

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {public:ListNode* deleteNode(ListNode* head, int val) {if(head->val==val) return head->next;ListNode* cur = head;ListNode* curLast = NULL;while(1){if(cur->val==val){//cout<<cur->val<<endl;curLast->next = cur->next;break;}else{curLast = cur;cur = cur->next;}}return head;}
};

19 [正则表达式匹配]

class Solution {public:bool isMatch(string s, string p) {int m = s.size();int n = p.size();vector<vector<int>> f(m+1,vector<int>(n+1));f[0][0] = true;for(int i=0;i<n;i++){if(p[i]=='*'&&(i==1||(i>=2&&f[0][i-1]))){f[0][i+1] = true;}}if(n>0&&p[1]=='*'){f[0][2] = true;}int ii,jj;for(int i=0;i<m;i++){for(int j=0;j<n;j++){// cout<<"i="<<i<<"j="<<j<<endl;ii = i+1;jj = j+1;// cout<<"here1"<<endl;if(p[j]!='*'){if(p[j]=='.'||p[j]==s[i]){// cout<<"here2"<<endl;f[ii][jj] = f[ii-1][jj-1];// cout<<"here3"<<endl;}}else{//cout<<"here3"<<endl;if(f[ii][jj-2]){f[ii][jj] = true;}else{if((p[j-1]=='.'||p[j-1]==s[i])&&f[ii-1][jj]){f[ii][jj] = true;}}}}}// cout<<"here4"<<endl;return f[m][n];}
};

20 [表示数值的字符串]

class Solution {public:enum State {STATE_INITIAL,STATE_INT_SIGN,STATE_INTEGER,STATE_POINT,STATE_POINT_WITHOUT_INT,STATE_FRACTION,STATE_EXP,STATE_EXP_SIGN,STATE_EXP_NUMBER,STATE_END};enum CharType {CHAR_NUMBER,CHAR_EXP,CHAR_POINT,CHAR_SIGN,CHAR_SPACE,CHAR_ILLEGAL};CharType toCharType(char ch) {if (ch >= '0' && ch <= '9') {return CHAR_NUMBER;} else if (ch == 'e' || ch == 'E') {return CHAR_EXP;} else if (ch == '.') {return CHAR_POINT;} else if (ch == '+' || ch == '-') {return CHAR_SIGN;} else if (ch == ' ') {return CHAR_SPACE;} else {return CHAR_ILLEGAL;}}bool isNumber(string s) {unordered_map<State, unordered_map<CharType, State>> transfer{{STATE_INITIAL, {{CHAR_SPACE, STATE_INITIAL},{CHAR_NUMBER, STATE_INTEGER},{CHAR_POINT, STATE_POINT_WITHOUT_INT},{CHAR_SIGN, STATE_INT_SIGN}}}, {STATE_INT_SIGN, {{CHAR_NUMBER, STATE_INTEGER},{CHAR_POINT, STATE_POINT_WITHOUT_INT}}}, {STATE_INTEGER, {{CHAR_NUMBER, STATE_INTEGER},{CHAR_EXP, STATE_EXP},{CHAR_POINT, STATE_POINT},{CHAR_SPACE, STATE_END}}}, {STATE_POINT, {{CHAR_NUMBER, STATE_FRACTION},{CHAR_EXP, STATE_EXP},{CHAR_SPACE, STATE_END}}}, {STATE_POINT_WITHOUT_INT, {{CHAR_NUMBER, STATE_FRACTION}}}, {STATE_FRACTION,{{CHAR_NUMBER, STATE_FRACTION},{CHAR_EXP, STATE_EXP},{CHAR_SPACE, STATE_END}}}, {STATE_EXP,{{CHAR_NUMBER, STATE_EXP_NUMBER},{CHAR_SIGN, STATE_EXP_SIGN}}}, {STATE_EXP_SIGN, {{CHAR_NUMBER, STATE_EXP_NUMBER}}}, {STATE_EXP_NUMBER, {{CHAR_NUMBER, STATE_EXP_NUMBER},{CHAR_SPACE, STATE_END}}}, {STATE_END, {{CHAR_SPACE, STATE_END}}}};int len = s.length();State st = STATE_INITIAL;for (int i = 0; i < len; i++) {CharType typ = toCharType(s[i]);if (transfer[st].find(typ) == transfer[st].end()) {return false;} else {st = transfer[st][typ];}}return st == STATE_INTEGER || st == STATE_POINT || st == STATE_FRACTION || st == STATE_EXP_NUMBER || st == STATE_END;}
};

一看这道题就比想做,抄一下题解答案吧。用的是有限状态自动机,简单地说,就是判断每一位,在每一位上,判断这一位的下一位要是什么样子才是 true 的,如果不满足直接 false,如果满足,转移到下一位进行判断。

21 [调整数组顺序使奇数位于偶数前面]

class Solution {public:vector<int> exchange(vector<int>& nums) {vector<int> result,rest;for(auto &it:nums){if(it%2){result.push_back(it);}else{rest.push_back(it);}}for(auto &it:rest){result.push_back(it);};return result;}
};

22 [链表中倒数第 k 个节点]

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {public:ListNode* getKthFromEnd(ListNode* head, int k) {int count = 1;auto cur = head;while(1){if(cur->next!=NULL){count++;cur = cur->next;}else{break;}}int s = count+1-k;cur = head;for(int i=0;i<s-1;i++){cur = cur->next;}return cur;}
};

24 [反转链表]

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {public:ListNode* reverseList(ListNode* head) {if(head==NULL) return NULL;if(head->next==NULL) return head;ListNode* cur = head;ListNode* next = cur->next;ListNode* last = NULL;ListNode* nextNext=next->next;while(1){//cout<<cur->val<<endl;cur->next = last;if(next!=NULL)next->next = cur;//cout<<"cur"<<cur->val<<"next"<<next->val<<endl;//<<"last"<<last->val<<endl;last = cur;cur = next;if(cur==NULL) break;next = nextNext;if(next!=NULL)nextNext = next->next;           }return last;}
};

要记录四个点。

25 [合并两个排序的链表]

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(l1==NULL) return l2;if(l2==NULL)  return l1;ListNode* head = new ListNode;ListNode* cur1(head);ListNode* cur2(head);if(l1->val<l2->val){head = l1;cur1 = l1->next;cur2 = l2;}else{head = l2;cur2 = l2->next;cur1 = l1;}auto cur = head;while(1){if(cur1==NULL){cur->next=cur2;return head;}if(cur2==NULL){cur->next = cur1;return head;}if(cur1->val<cur2->val){cur->next = cur1;cur1 = cur1->next;cur = cur->next;}else{cur->next = cur2;cur2 = cur2->next;cur = cur->next;}}return head;}
};

只有定义的链表指向的东西内容相同时,才能相互地赋值。

26 [树的子结构]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:bool recursion(TreeNode* A, TreeNode* B) {if(A==NULL&&B!=NULL) return false;if(B==NULL) return true;return (A->val==B->val)&&recursion(A->left,B->left)&&recursion(A->right,B->right);};bool isSubStructure(TreeNode* A, TreeNode* B) {//cout<<"A val"<<A->val<<" "<<"B val"<<B->val<<endl;if(B==NULL) return false;if(A==NULL) return false;if(recursion(A,B)) return true;if(isSubStructure(A->left,B)) return true;if(isSubStructure(A->right,B)) return true;return false;};
};

27 [二叉树的镜像]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:TreeNode* mirrorTree(TreeNode* root) {if(root==NULL) return root;auto tmp = root->left;root->left = root->right;root->right = tmp;mirrorTree(root->left);mirrorTree(root->right);return root;}
};

28 [对称的二叉树]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:bool isSym(TreeNode* left,TreeNode* right){if(left==NULL&&right==NULL) return true;if(left==NULL&&right!=NULL) return false;if(left!=NULL&&right==NULL) return false;return (left->val==right->val)&&isSym(left->left,right->right)&&isSym(left->right,right->left);}bool isSymmetric(TreeNode* root) {if(root==NULL) return true;auto left = root->left;auto right = root->right;return isSym(left,right);}
};

29 [顺时针打印矩阵]

class Solution {vector<vector<int>> matrixG;vector<int> result;
public:void printSq(int i,int len1,int len2){if(len1==1){for(int s=i;s<=i+len2-1;s++){result.push_back(matrixG[i][s]);}return;}if(len2==1){for(int s=i;s<=i+len1-1;s++){result.push_back(matrixG[s][i]);}return;}int n1 = i+len1-1;int n2 = i+len2-1;for(int k=i;k<=n2-1;k++){//cout<<matrixG[i][k]<<endl;result.push_back(matrixG[i][k]);}for(int k=i;k<=n1-1;k++){//cout<<matrixG[k][n]<<endl;result.push_back(matrixG[k][n2]);}for(int k=n2;k>i;k--){//cout<<matrixG[n-1][k]<<endl;result.push_back(matrixG[n1][k]);}for(int k=n1;k>i;k--){//cout<<matrixG[k][i]<<endl;result.push_back(matrixG[k][i]);}}vector<int> spiralOrder(vector<vector<int>>& matrix) {matrixG = matrix;int len1,len2;int size1 = matrix.size();if(size1==0) return result;int size2 = matrix[0].size();for(int i=0;i<round(min(size1,size2)/2.0);i++){len1 = size1-2*(i);len2 = size2-2*(i);printSq(i,len1,len2);}return result;}
};

30 [包含 min 函数的栈]

class MinStack {stack<int> stk;
public:/** initialize your data structure here. */MinStack() {}void push(int x) {stk.push(x);}void pop() {stk.pop();}int top() {return stk.top();}int min() {int m = stk.top();stack<int> tmp;while(!stk.empty()){m = stk.top()<m?stk.top():m;tmp.push(stk.top());stk.pop();}while(!tmp.empty()){stk.push(tmp.top());tmp.pop();}return m;}
};/*** Your MinStack object will be instantiated and called as such:* MinStack* obj = new MinStack();* obj->push(x);* obj->pop();* int param_3 = obj->top();* int param_4 = obj->min();*/

这是个超时的版本,下面提供一个不超时的版本。

class MinStack {stack<int> stk;stack<int> tmp;
public:/** initialize your data structure here. */MinStack() {//  cout<<0<<endl;}void push(int x) {stk.push(x);if(tmp.empty()||x<=tmp.top()){tmp.push(x);}//  cout<<1<<endl;}void pop() {if(stk.top()==tmp.top())tmp.pop();stk.pop();//  cout<<2<<endl;}int top() {// cout<<3<<endl;return stk.top();}int min() {// cout<<4<<endl;return tmp.top();}
};/*** Your MinStack object will be instantiated and called as such:* MinStack* obj = new MinStack();* obj->push(x);* obj->pop();* int param_3 = obj->top();* int param_4 = obj->min();*/

31 [栈的压入、弹出序列]

class Solution {
public:bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {if(popped.size()==0) return true;stack<int> stk;int ind = 0;for(auto &it:pushed){//cout<<it<<endl;stk.push(it);while(!stk.empty()&&stk.top()==popped[ind]){//cout<<stk.top()<<endl;stk.pop();ind++;//cout<<ind<<endl;if(ind==popped.size()) return true;}}return false;}
};

32-I [从上到下打印二叉树]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:vector<int> levelOrder(TreeNode* root) {vector<int> res;if(root==NULL) return res;vector<TreeNode*> queue;queue.push_back(root);while(!queue.empty()){auto node = queue[0];queue.erase(queue.begin());res.push_back(node->val);if(node->left!=NULL) queue.push_back(node->left);if(node->right!=NULL) queue.push_back(node->right);}return res;}
};

32-II [从上到下打印二叉树 II]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> res;vector<int> layer;vector<TreeNode*> F1;vector<TreeNode*> F2;F1.push_back(root);while(!F1.empty()){for(auto& it:F1){if(it==NULL) continue;layer.push_back(it->val);F2.push_back(it->left);F2.push_back(it->right);}if(!layer.empty())res.push_back(layer);  layer.clear();F1.clear();F1 = F2;F2.clear();} return res;}
};

32-III [从上到下打印二叉树 III]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> res;vector<int> layer;vector<TreeNode*> F1;vector<TreeNode*> F2;F1.push_back(root);int i=0;while(!F1.empty()){for(auto& it:F1){if(it==NULL) continue;layer.push_back(it->val);F2.push_back(it->left);F2.push_back(it->right);}if(!layer.empty()){if(i%2==1)reverse(layer.begin(),layer.end());res.push_back(layer);  }layer.clear();F1.clear();F1 = F2;F2.clear();i++;} return res;}
};

33 [二叉搜索树的后序遍历序列]

class Solution {bool recursion(int i,int j,vector<int>& postorder){if(i>=j) return true;int p = i;while(postorder[p]<postorder[j]) p++;int m = p;while(postorder[p]>postorder[j]) p++;return p==j&&recursion(i,m-1,postorder)&&recursion(m,j-1,postorder);}public:bool verifyPostorder(vector<int>& postorder) {return recursion(0, postorder.size() - 1,postorder);}
};

二叉搜索树的定义就是左中右依次变大。根据定义找到重点,再判断左右子树即可。

34 [二叉树中和为某一值的路径]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {public:vector<vector<int>> result;void dfs(TreeNode* root,int target,vector<int> res,int sum){if(root==NULL) return;sum+=root->val;res.push_back(root->val);if(root->left==NULL&&root->right==NULL&&sum==target){//cout<<"sum"<<sum<<endl;//"root.val"<<root->val<<endl;result.push_back(res);return;}if(root->left==NULL&&root->right==NULL&&sum!=target){return;}//cout<<"root.val"<<root->val<<endl;dfs(root->left,target,res,sum);dfs(root->right,target,res,sum);return;}vector<vector<int>> pathSum(TreeNode* root, int target) {vector<int> res;int sum = 0;dfs(root,target,res,sum);return result;}
};

35 [复杂链表的复制]

/*
// Definition for a Node.
class Node {
public:int val;Node* next;Node* random;Node(int _val) {val = _val;next = NULL;random = NULL;}
};
*/
class Solution {unordered_map<Node*, Node*> cachedNode;
public:Node* copyRandomList(Node* head) {if(head==NULL) return NULL;auto cur = head;Node* vir = new Node(0);Node* oldNode = vir;while(1){Node* newNode = new Node(cur->val);cachedNode[cur] = newNode;oldNode->next = newNode;cur = cur->next;oldNode = newNode;if(cur==NULL) break;  }auto head1 = vir->next;cur = head1;auto cur1 = head;while(cur!=NULL){cur->random = cachedNode[cur1->random];cur = cur->next;cur1 = cur1->next;}return head1;}
};

建点的时候,和原链搞个一一映射。

36 [二叉搜索树与双向链表]

/*
// Definition for a Node.
class Node {
public:int val;Node* left;Node* right;Node() {}Node(int _val) {val = _val;left = NULL;right = NULL;}Node(int _val, Node* _left, Node* _right) {val = _val;left = _left;right = _right;}
};
*/
class Solution {private:Node *pre, *head;void dfs(Node* cur) {if(cur == NULL) return;dfs(cur->left);if(pre != NULL) pre->right = cur;else head = cur;cur->left = pre;pre = cur;dfs(cur->right);}
public:Node* treeToDoublyList(Node* root) {if(root == NULL) return NULL;dfs(root);head->left = pre;pre->right = head;return head;}};

把二叉搜索树通过中序遍历变成一个有序的双向链表。

37 [序列化二叉树]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Codec {public:void rserialize(TreeNode* root, string& str) {if (root == NULL) {str += "None,";} else {str += to_string(root->val) + ",";rserialize(root->left, str);rserialize(root->right, str);}}TreeNode* rdeserialize(list<string>& dataArray) {if (dataArray.front() == "None") {dataArray.erase(dataArray.begin());return NULL;}TreeNode* root = new TreeNode(stoi(dataArray.front()));dataArray.erase(dataArray.begin());root->left = rdeserialize(dataArray);root->right = rdeserialize(dataArray);return root;}string serialize(TreeNode* root) {string ret;rserialize(root, ret);cout<<ret<<endl;return ret;}TreeNode* deserialize(string data) {list<string> dataArray;string str;for (auto& ch : data) {if (ch == ',') {dataArray.push_back(str);str.clear();} else {str.push_back(ch);}}if (!str.empty()) {dataArray.push_back(str);str.clear();}return rdeserialize(dataArray);}
};// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

先序遍历是很容易地在二叉树和字符串之间转换和复原的。深度优先搜索的三种遍历总是唯一地决定了树的结构。

38 [字符串的排列]

class Solution {int size;vector<string> result;void recursion(string s,vector<bool> posUsed,string res){if(res.size()==size){result.push_back(res);return;}for(int i=0;i<size;i++){if(posUsed[i]) continue;res.push_back(s[i]);posUsed[i] = true;recursion(s,posUsed,res);posUsed[i] = false;res.pop_back();}}public:vector<string> permutation(string s) {size = s.size();vector<bool> posUsed(size,false);string res;recursion(s,posUsed,res);sort(result.begin(), result.end());result.erase(unique(result.begin(), result.end()), result.end());return result;}
};

先排序之后,unique 才能起作用。典型的回溯暴力搜索。

39 [数组中出现次数超过一半的数字]

方法一: 哈希表(时间 O ( n ) O(n) O(n),空间 O ( n ) O(n) O(n))

#include <iostream>
#include<vector>
#include<unordered_map>
using namespace std;
int main() {vector<int> a = { 1,2,3,2,2,2,5,4,2 };int n = a.size();unordered_map<int, int> M;for (int i = 0;i < n;i++){M[a[i]]++;}for (auto& it : M){if (it.second > n / 2){cout << it.first << endl;}}return 0;
}

方法二: 快速排序+剪枝(时间 O ( n ) O(n) O(n))

#include <iostream>
#include<vector>
using namespace std;
int swap(vector<int>& nums, int i, int j)
{int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;return 0;
}
int qsort(vector<int>& nums, int left, int right)
{if (left >= right) return 0;int std = nums[left];int i = left;int j = right;while (1){if (i >= j) break;while (1){if (j <= i || nums[j] < std) break;j--;}while (1){if (i >= j || nums[i] > std) break;i++;}if (i < j) swap(nums, i, j);}int n = nums.size();swap(nums, left, j);if (abs(2 * j - n + 1) <= 1) return nums[j];else if (j < n / 2) return qsort(nums, j + 1, right);else return qsort(nums, left, j - 1);return 0;
}
int main() {vector<int> nums = { 1,2,3,2,2,2,5,4,2 };int result = qsort(nums, 0, nums.size() - 1);cout << result << endl;return 0;
}

40 [最小的 k 个数]

class Solution {public:vector<int> getLeastNumbers(vector<int>& arr, int k) {sort(arr.begin(),arr.end());vector<int> r(k);for(int i=0;i<k;i++){r[i] = arr[i];}return r;}
};

可以用排序吗?

41 [数据流中的中位数]

class MedianFinder {public:/** initialize your data structure here. */priority_queue<int,vector<int>,greater<int>> maxHeap;priority_queue<int,vector<int>,less<int>> minHeap;MedianFinder() {}void addNum(int num) {if(maxHeap.size()==minHeap.size()){maxHeap.push(num);minHeap.push(maxHeap.top());maxHeap.pop();}else{minHeap.push(num);maxHeap.push(minHeap.top());minHeap.pop();}}double findMedian() {if(minHeap.size()==maxHeap.size()){return (maxHeap.top()+minHeap.top())/2.0;}else{return minHeap.top();}}
};/*** Your MedianFinder object will be instantiated and called as such:* MedianFinder* obj = new MedianFinder();* obj->addNum(num);* double param_2 = obj->findMedian();*/

小顶堆大顶堆的思路。
priority_queue<int,vector,greater> maxHeap;
priority_queue<int,vector,less> minHeap;

42 [连续子数组的最大和]

class Solution {public:int maxSubArray(vector<int>& nums) {int size  = nums.size();int m = nums[0];for(int i=0;i<size;i++){int s = 0;for(int j=i;j<size;j++){s+=nums[j];m = max(m,s);          }}return m;}
};

超时版本。

class Solution {public:int maxSubArray(vector<int>& nums) {int pre = 0, M = nums[0];for (auto &it: nums) {pre = max(pre + it, it);M = max(M, pre);}return M;}
};

f(i) 代表以第 i 个数结尾的。动态转移方法一定要搞清楚转移的量是什么。

43 [1 ~ n 整数中 1 出现的次数]

class Solution {public:int countDigitOne(int n) {long long mulk = 1;int ans = 0;for (int k = 0; n >= mulk; ++k) {ans += (n / (mulk * 10)) * mulk + min(max(n % (mulk * 10) - mulk + 1, 0LL), mulk);mulk *= 10;}return ans;}
};

分别统计每个数位,寻找规律。

44 [数字序列中某一位的数字]

class Solution {public:int findNthDigit(int n) {if(n<10) return n;int k=1;n = n-10;while(1){k++;if(n>=k*9*pow(10,k-1)){n-=k*9*pow(10,k-1);}else{break;}}int p = n/k;int d = n%k;//cout<<"n="<<n<<"p="<<p<<"d="<<d<<endl;int result = pow(10,k-1)+p;result = result/pow(10,k-d-1);result = result%10;return result;}
};

下标搞不清楚,举个简单的例子去想就可以了。

45 [把数组排成最小的数] 排序

class Solution {public:bool static cmp(string &x,string &y){if(x+y<y+x) return true;return false;}string minNumber(vector<int>& nums) {vector<string> strs;string res;for(int i = 0; i < nums.size(); i++)strs.push_back(to_string(nums[i]));//to_string 可以把数字常量包括小数转为字符串sort(strs.begin(), strs.end(), cmp);for(int i = 0; i < strs.size(); i++)res.append(strs[i]);//可用 + 替代return res;}
};

sort 的第三个参数需要时静态的,否则报错。

46 [把数字翻译成字符串]

class Solution {public:int translateNum(int num) {vector<int> nums;while(1){nums.push_back(num%10);num = num/10;if(num==0) break;}reverse(nums.begin(),nums.end());int sz = nums.size();vector<int> dp(sz+1);dp[0] = 1;dp[1] = 1;for(int i=2;i<=sz;i++){dp[i] = dp[i-1];if(nums[i-2]==1||(nums[i-2]==2&&nums[i-1]<=5)){dp[i] +=dp[i-2];}}return dp[sz];}
};

典型的动态规划题目。

47 [礼物的最大价值] 动态规划

class Solution {public:int maxValue(vector<vector<int>>& grid) {int m = grid.size();int n = grid[0].size();vector<vector<int>> dp(m,vector<int>(n));//dp[0][0] = grid[0][0];for(int i=0;i<m;i++){for(int j=0;j<n;j++){if(i==0&&j==0){dp[i][j] = grid[i][j];}else if(i==0){dp[i][j] = dp[i][j-1]+grid[i][j];}else if(j==0){dp[i][j] = dp[i-1][j] + grid[i][j];}else{dp[i][j] = max(dp[i-1][j],dp[i][j-1])+grid[i][j];}}}return dp[m-1][n-1];}
};

48 [最长不含重复字符的子字符串]

class Solution {public:int lengthOfLongestSubstring(string s) {if(s=="") return 0;int sz = s.size();vector<int> dp(sz);dp[0] = 1;int a = 0;int M = 1;for(int i=1;i<sz;i++){int j;for(j = i-1;j>=a;j--){if(s[j]==s[i]){a = j;dp[i] = i-j;break;}//cout<<a<<" "<<j<<endl;}if(j<a){//cout<<a<<" "<<j<<endl;//cout<<dp[i]<<" "<<dp[i-1]<<endl;dp[i] = dp[i-1]+1;M = max(dp[i],M);}}//for(auto &it:dp)//{//   cout<<"dp="<<it<<endl;//}return M;}
};

动态规划的关键在于找 dp 含义,以及转移方程。这种拼接类型的,一般可以考虑“以xx为结尾的值”为 dp。

49 [丑数]

class Solution {public:int nthUglyNumber(int n) {vector<int> dp(n+1);dp[1] = 1;int p1 = 1,p2 = 1,p3 = 1;for(int i=2;i<=n;i++){dp[i] = min(min(2*dp[p1],3*dp[p2]),5*dp[p3]);if(dp[i]==2*dp[p1]){p1++;}if(dp[i]==3*dp[p2]){p2++;}if(dp[i]==5*dp[p3]){p3++;}}return dp[n];}
};

新产生的和谁的相等,指针就下移一个。

50 [第一个只出现一次的字符]

class Solution {public:char firstUniqChar(string s) {unordered_map<char,int> map;for(auto &it:s){map[it]++;}for(auto &it:s){if(map[it]==1){return it;}}return ' ';}
};

哈希表处理简单问题真好用。

51 [数组中的逆序对]

class Solution {int result = 0;int merge(vector<int> &nums,int left,int mid,int right){//cout<<left<<" "<<mid<<" "<<right<<endl;vector<int> L(nums.begin()+left,nums.begin()+mid+1);vector<int> R(nums.begin()+mid+1,nums.begin()+right+1);//cout<<"Li="<<L[0]<<endl;//cout<<"Rj="<<R[0]<<endl;int i=0;int j=0;int l1 = mid-left+1;int l2 = right-mid;int s=left;//cout<<left<<" "<<mid<<" "<<right<<endl;while(1){if(i==l1){//cout<<left<<" "<<mid<<" "<<right<<endl;for(int k=j;k<l2;k++){nums[s] = R[k];s++;}return 0;}if(j==l2){//cout<<left<<" "<<mid<<" "<<right<<endl;for(int k=i;k<l1;k++){nums[s] = L[k];s++;}return 0;}if(L[i]<=R[j]){nums[s] = L[i];i++;}else{//cout<<"here"<<endl;nums[s] = R[j];result+=l1-i;j++;}s++;//cout<<left<<" "<<mid<<" "<<right<<endl;}}int mergeSort(int left,int right,vector<int> &nums){if(left==right){return 0;}int mid  = (left+right)/2;mergeSort(left,mid,nums);mergeSort(mid+1,right,nums);merge(nums,left,mid,right);return 0;}
public:int reversePairs(vector<int>& nums) {if(nums.empty()) return 0;mergeSort(0,nums.size()-1,nums);return result;}
};

归并排序加一行结果计数。

52 [两个链表的第一个公共节点] 链表

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {unordered_map<ListNode*,int> map;auto cur  = headA;while(cur!=NULL){map[cur]++;cur = cur->next;}cur = headB;while(cur!=NULL){if(map.find(cur)!=map.end()){return cur;}cur = cur->next;}return NULL;}
};

哈希 map 是个好东西。

53-I [在排序数组中查找数字 I]

class Solution {public:int search(vector<int>& nums, int target) {unordered_map<int,int> map;for(auto &it:nums){map[it]++;}return map[target];}
};

53-II [0 ~ n-1 中缺失的数字]

class Solution {public:int missingNumber(vector<int>& nums) {for(int i=0;i<nums.size();i++){if(nums[i]!=i){return i;}}return nums.size();}
};

54 [二叉搜索树的第 k 大节点]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {vector<int> v;void recursion(TreeNode* root){if(root==NULL) return;recursion(root->left);v.push_back(root->val);//cout<<root->val<<endl;recursion(root->right);}
public:int kthLargest(TreeNode* root, int k) {recursion(root);return v[v.size()-k];}
};

55-I [二叉树的深度]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {int depth;void recursion(TreeNode* root,int d){if(root==NULL){//cout<<" "<<d<<endl;depth = max(depth,d);return;}//cout<<d<<endl;//cout<<root->val<<endl;recursion(root->left,d+1);recursion(root->right,d+1);return;}
public:int maxDepth(TreeNode* root) {depth = 0;int d = 0;recursion(root,d);return depth;}
};

函数调用的时候传入参数写成 d++,那么传入的还是 d。

55-II [平衡二叉树]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:int height(TreeNode* root) {if (root == NULL) {return 0;} else {return max(height(root->left), height(root->right)) + 1;}}bool isBalanced(TreeNode* root) {if (root == NULL) {return true;} else {return abs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);}}
};

平衡二叉树,可以递归地定义为:“当前点的高度差小于 1,并且左右子树都是满足该定义下的平衡二叉树”。两递归做法。

56-I [数组中数字出现的次数]

class Solution {public:vector<int> singleNumbers(vector<int>& nums) {int r = 0;for(auto &it:nums){r = r^it;}vector<int> a;vector<int> b;int k = 0;while(1){if(r>>k&1) break;k++;}for(auto &it:nums){if(it>>k&1) a.push_back(it);else b.push_back(it);}vector<int> result;r = 0;for(auto &it:a){r = r^it;}result.push_back(r);r = 0;for(auto &it:b){r = r^it;}result.push_back(r);return result;}
};

2 2 分组异或。

56-II [数组中数字出现的次数 II]

class Solution {public:int singleNumber(vector<int>& nums) {unordered_map<int,int> map;for(auto &it:nums){map[it]++;}for(auto &it:map){if(it.second==1){return it.first;}}return 0;}
};

57 [和为 s 的两个数字]

class Solution {public:vector<int> twoSum(vector<int>& nums, int target) {int sz = nums.size();int i = 0;int j = sz-1;int a,b;while(1){if(i==j) break;a = nums[i];b = nums[j];if(a+b==target) break;if(a+b>target){j--;continue;}if(a+b<target){i++;continue;}}vector<int> result;result.push_back(a);result.push_back(b);return result;}
};

双指针法,妙啊。

57-II [和为 s 的连续正数序列]

class Solution {public:vector<vector<int>> findContinuousSequence(int target) {double sum;vector<vector<int>> result;vector<int> tmp;for(int i=1;i<target;i++){//sum = i;for(int j=i+1;j<target;j++){sum = (i+j)/2.0*(j-i+1);//sum = sum+j;if(sum>target) break;//if(abs(sum-target)<0.1)if(sum==target){tmp.clear();           for(int k=i;k<=j;k++){        tmp.push_back(k);   }result.push_back(tmp);}}}return result;}
};

58-I [翻转单词顺序]

class Solution {public:string reverseWords(string s) {s+=" ";//预处理int n = s.size();vector<string> res;string tmp = "";for(int i=0;i<n;i++){if(s[i]==' '){if(tmp.empty()){continue;}res.push_back(tmp);tmp.clear();}else{tmp.push_back(s[i]);}}reverse(res.begin(),res.end());string result = "";for(int i=0;i<res.size();i++){result+=res[i];if(i!=res.size()-1){result+=" ";}}return result;}
};

找到“xxx空”的模式,空的时候压入临时字符串。遇到空格的时候,如果临时字符串为空,说明还没开始压字母呢,说明肯定不是字母后面的那个空格,直接跳过即可。
最好在初始字符串后面补一个空格。

58-II [左旋转字符串]

class Solution {public:string reverseLeftWords(string s, int n) {string result = "";int sz = s.size();for(int i=n;i<sz;i++){result.push_back(s[i]);}for(int i=0;i<n;i++){result.push_back(s[i]);}return result;}

};

59-I [滑动窗口的最大值]

class Solution {public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {if(nums.empty()) return {};int n = nums.size();priority_queue<pair<int, int>> q;//用 priority_queue 构造大顶堆,默认就是这个for (int i = 0; i < k; ++i) {q.emplace(nums[i], i);}vector<int> ans = {q.top().first};//最初窗口的最大值for (int i = k; i < n; ++i) {//开始滑动q.emplace(nums[i], i);while (q.top().second <= i - k) {//最大值在窗口之前,就 pop 掉。q.pop();}ans.push_back(q.top().first);}return ans;}
};

大顶堆的巧妙应用。判断最大值是否在窗口中,不在的话采用 pop 的思路去掉。

59-II [队列的最大值]

class MaxQueue {int q[20000];int begin = 0, end = 0;
public:MaxQueue() {}int max_value() {int ans = -1;for (int i = begin; i != end; ++i)ans = max(ans, q[i]);return ans;}void push_back(int value) {q[end] = value;end++;}int pop_front() {if (begin == end)return -1;begin++;return q[begin-1];}
};
/*** Your MaxQueue object will be instantiated and called as such:* MaxQueue* obj = new MaxQueue();* int param_1 = obj->max_value();* obj->push_back(value);* int param_3 = obj->pop_front();*/

用数组进行暴力构造即可。

60 [n 个骰子的点数]

class Solution {public:vector<double> dicesProbability(int n) {vector<double> dp0(6,1.0/6);for(int i=2;i<=n;i++){vector<double> dp(5*i+1,0);for(int j=1;j<=6;j++){for(int k=0;k<dp0.size();k++){dp[k+j-1] = dp[k+j-1]+1.0/6*dp0[k];cout<<dp[k+j-1]<<endl;}}//cout<<dp[5*i]<<endl;dp0 = dp;}return dp0;}
};

动态规划替代概率计算。

61 [扑克牌中的顺子]

class Solution {public:bool isStraight(vector<int>& nums) {sort(nums.begin(),nums.end());int num_zero = 0;for(int i=0;i<nums.size();i++){if(nums[i]==0){num_zero++;}else{break;}}//cout<<nums.size()<<endl;//int s = 0;for(int i=0;i<nums.size()-1;i++){if(nums[i]==0) continue;//cout<<nums[i+1]-nums[i]<<endl;if(nums[i+1]==nums[i]) return false;//sum+=nums[i+1]-nums[i];}int s = nums[nums.size()-1] - nums[num_zero];if(nums.size()-1<s){return false;}return true;}
};

62 [圆圈中最后剩下的数字]

class Solution {int recursion(int n,int m){if(n==1){return 0;}int r = (recursion(n-1,m)+m)%n;return r;}
public:int lastRemaining(int n, int m) {return recursion(n,m);}
};

动态规划,转移方程为 f ( n , m ) = [ ( f ( n − 1 ) , m ) + m ] % n f(n,m) =[ (f(n-1),m)+m]\%n f(n,m)=[(f(n−1),m)+m]%n。想清楚这一点非常重要。

暴力解法超时如下:

class Solution {
public:int lastRemaining(int n, int m) {vector<int> a(n);for(int i=0;i<n;i++){a[i] = i;}int iter = -1;for(int i=0;i<n-1;i++){int j = 0;while(1){iter++;iter = iter%n;// cout<<iter<<" "<<j <<endl;if(a[iter]!=-1){j++;}if(j==m){//cout<<a[iter]<<endl;a[iter] = -1;                  break;}}}int result;for(auto &it:a){if(it!=-1){result = it;break;}}return result;}
};

63 [股票的最大利润]

class Solution {public:int maxProfit(vector<int>& prices) {int r = 0;for(int i=0;i<prices.size();i++){for(int j=i+1;j<prices.size();j++){r = max(r,prices[j]-prices[i]);}}return r;}
};

暴力搞掉它了。

64 [求 1+2+…+n]

class Solution {public:int sumNums(int n) {n-1&&(n = n+sumNums(n-1));return n;}
};

不能用见加减乘除,循环条件判断等,那么只能用 && 找出递归出口了。

65 [不用加减乘除做加法]

class Solution {public:int add(int a, int b) {int c;while(c!=0){int n = a^b;c = (unsigned)(a & b)<<1; a = n;b = c;}return a;}
};

本位和进位,不断循环。

66 [构建乘积数组]

class Solution {public:vector<int> constructArr(vector<int>& a) {if(a.empty()) return {};int sz = a.size();vector<int> B(sz);vector<int> A(sz);int s = 1;int s1 = 1;for(int i=sz-1;i>=0;i--){s*=a[i];B[i] = s;s1 *= a[sz-1-i];A[sz-1-i] = s1;}vector<int> result;result.push_back(B[1]);for(int i=1;i<sz-1;i++){result.push_back(A[i-1]*B[i+1]);}result.push_back(A[sz-2]);return result;}
};

分成两段计算。

67 [把字符串转换成整数]

class Solution {
public:int strToInt(string str) {int flag=1;int tmp;long int result = 0;bool begin = false;for(int i=0;i<str.size();i++){cout<<str[i]<<endl;if(str[i]==' '){if(begin==false){continue;    }else{break;}}else if(str[i]=='+'){if(begin==false){flag = 1;begin = true; }else{break;}}else if(str[i]=='-'){if(begin==false){flag = -1;begin = true;}else{break;}}else if(str[i]-'0'<=9&&str[i]-'0'>=0){begin = true;tmp = str[i] - '0';result = result*10+tmp;if(result<INT_MIN||result>INT_MAX){if(flag>0){return flag*INT_MAX;}else{return INT_MIN;}}//cout<<flag<<endl;  }else{break;}}//cout<<str[str.size()-1]<<endl;return flag*result;}
};

严格遵守想法和步骤慢慢写。

68-I [二叉搜索树的最近公共祖先]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {TreeNode* recursion(TreeNode* root,int a,int b){int value = root->val;int m = min(a,b);int M = max(a,b);if(value>=m&&value<=M){return root;}if(value<m){return recursion(root->right,a,b);}else{return recursion(root->left,a,b);}}
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {return recursion(root,p->val,q->val);     }
};

68-II [二叉树的最近公共祖先]

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {public:TreeNode* res;bool recursion(TreeNode* root, TreeNode* p, TreeNode* q) {//判断以root为节点的数是否包含至少一个节点if (root == NULL) return false;bool lson = recursion(root->left, p, q);bool rson = recursion(root->right, p, q);if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {res = root;} //递归的同时捕捉公共节点的情况return lson || rson || (root->val == p->val || root->val == q->val);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {recursion(root, p, q);return res;}
};

补充题

N皇后

class Solution {vector<vector<string>> result;vector<int> pos;int nG;int fresh( vector<vector<bool>> &M,int i,int j){int sum = i+j;int sub = i-j;for(int i=0;i<nG;i++){for(int j=0;j<nG;j++){if(i+j==sum||i-j==sub){M[i][j] = true;}}}return 0;}int pos2StrAndSave(){//vector<string> str(nG,"....");string tmp(nG,'.');vector<string> *str = new vector<string>(nG,tmp);for(int i=0;i<nG;i++){(*str)[i][pos[i]] = 'Q';}result.push_back(*str);return 0;}int recursion(int m,vector<bool> colOccu,vector<vector<bool>> M){if(m>=nG){pos2StrAndSave();return 0;} for(int j=0;j<nG;j++){if(colOccu[j]) continue;if(M[m][j]) continue;pos[m]= j;//cout<<m<<" "<<j<<endl;auto M_back = M;auto colOccu_back = colOccu;colOccu[j] = true;fresh(M,m,j);recursion(m+1,colOccu,M);M = M_back;colOccu = colOccu_back;}return 0;}
public:vector<vector<string>> solveNQueens(int n) {vector<bool> colOccu(n,false);vector<vector<bool>> M(n,vector<bool>(n,false));nG = n;pos.resize(n);recursion(0,colOccu,M);return result;}
};

利用每行有且只有一个,根据行来遍历,能减少不少的工作量。想好了再动手,磨刀不误砍柴功。
如果要返回的结果是要占用新开辟的内存,那就不能把函数的局部变量存下来,这样函数返回了,这块内存也就消失了,应该用 new。
new 出来的数组是个指针,想要用它的下标索引复制,最好加个 *,如 (*str)[i][pos[i]] = 'Q';。有时候,并不是和 c 一样,首指针就表示数组。
回溯的题目,如果在 for 循环里面调用递归,记得每一次循环都一定一定一定要还原改变的值。

快速排序

#include <iostream>
#include<vector>
#include<algorithm>
//#include<bits/stdc++.h>
using namespace std;//i 从最左边元素(标兵)开始,j 从最右边元素开始
//j 找小于 std 的元素,i 找大于 std 的元素,j 先走(标兵在左,先走兵在右,平衡了)
//i==j 的时候,交换 std 与 j 的元素
//循环为 1+2 模式,一个循环内有两个循环,其一为右标兵移动,其二为左标兵移动
//其余问题代码写得很清楚,看代码int swap(vector<int> &nums, int i, int j)
{int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;return 0;
}int qsort(vector<int> &nums,int left,int right)
{if (left >= right) return 0;//左边大等于右边,就返回,仅写 == ,对于两个元素的时候,不够鲁棒int std = nums[left];int i = left;//左边就是从标兵位置开始,这样两个元素的时候才不会出 bugint j = right;while (1){if (i >= j) break;while (1)//一定要右边先开始{if (j <= i || nums[j] < std)//左右指针相遇或者找到比标兵小的数就退出{break;}j--;}while (1){if (i >= j || nums[i] > std){break;}i++;}if (i < j){swap(nums, i, j);}}swap(nums, left, j);//跳出 i++ 和 j-- 之后再来交换qsort(nums, left, j - 1);qsort(nums, j + 1, right);return 0;
}int main() {vector<int> nums = { 1,3,1,4,5,2,0 };qsort(nums,0,nums.size()-1);for (auto& it : nums){cout << it << endl;}return 0;}

//i 从最左边元素(标兵)开始,j 从最右边元素开始
//j 找小于 std 的元素,i 找大于 std 的元素,j 先走(标兵在左,先走兵在右,平衡了)
//i==j 的时候,交换 std 与 j 的元素
//循环为 1+2 模式,一个循环内有两个循环,其一为右标兵移动,其二为左标兵移动
//左右兵的判断条件除了和标兵比,还有看看是不是相遇了,相遇了就跳出循环动标兵,没相遇就继续找
//其余问题代码写得很清楚,看代码

486.预测赢家

class Solution {public:bool PredictTheWinner(vector<int>& nums) {int n = nums.size();vector<vector<int>> dp(n,vector<int>(n));for(int i=0;i<n;i++){dp[i][i] = nums[i];}for(int i=n-2;i>=0;i--){for(int j=i+1;j<n;j++){dp[i][j] = max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1]);}}return dp[0][n-1]>=0;}
};

用二维数组 dp[i][j] 来表示当面临 i 位置到 j 位置的数组时,当前决策者能获得的最大分数差。最大分数差表示的是自己的分减去别人的分,决策者令它尽可能大。

《剑指 Offer(第 2 版)》系列刷题相关推荐

  1. 剑指offer第2版Python题解(更新中)

    O(n^2)排序 冒泡排序.插入排序与选择排序(Python)_NLP_victor的博客-CSDN博客 归并 归并排序(Python)_NLP_victor的博客-CSDN博客 快排 快速排序(Py ...

  2. 【剑指offer】Java版代码(完整版)

    参考链接 [剑指offer]Java版代码(完整版)

  3. 剑指offer(第二版)读书笔记以及编程题目python版答案(二)

    剑指offer(第二版)读书笔记以及编程题目python版答案(二) 题目五:青蛙跳台阶 github地址: https://github.com/ciecus/leetcode_answers/tr ...

  4. 剑指Offer(第二版)面试题56:数组中数字出现的次数

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/73609133冷血之心的博客) 剑指Offer(第二版)面试题56: ...

  5. 【LeetCode】《剑指Offer》第Ⅴ篇⊰⊰⊰ 39 - 47题

    [LeetCode]<剑指Offer>第Ⅴ篇⊰⊰⊰ 39 - 47题 文章目录 [LeetCode]<剑指Offer>第Ⅴ篇⊰⊰⊰ 39 - 47题 39. 数组中出现次数超过 ...

  6. 【LeetCode】《剑指Offer》第Ⅰ篇⊰⊰⊰ 3 - 11题

    [LeetCode]<剑指Offer>第Ⅰ篇⊰⊰⊰ 3 - 11题 文章目录 [LeetCode]<剑指Offer>第Ⅰ篇⊰⊰⊰ 3 - 11题 03. 数组中重复的数字(ea ...

  7. LeetCode刷题 _「剑指 Offer]专项突破版

    第01天 整数 剑指 Offer II 001. 整数除法 class Solution:# 时间复杂度:O(logn), 空间复杂度:O(1)def divideCore(self, dividen ...

  8. 【剑指Offer专题】链表系列:从尾到头打印链表、反转链表、回文链表、合并两个排序的链表(C++和Python实现)...

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 剑指Offer(三):从尾到头打印链表 输入一个链表的头节点,从尾到头反过来返回每 ...

  9. 剑指offer有python版吗_剑指Offer算法类题目[Python版]

    标签:重复   作用   coding   面试   medium   mba   none   fas   utf-8 面试题012 数值的整数次方 解题思路1 考虑所有情况,循环连乘 代码: de ...

  10. 剑指Offer(JS版)

    字符串的排列 题目描述: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. ...

最新文章

  1. d3.js多个x轴y轴canvas柱状图
  2. 微型计算机引脚,微型计算机硬件基础8086引脚.doc
  3. ActiveMQ部署模式
  4. Google C++单元测试框架GoogleTest---AdvancedGuide(译文)上
  5. java游戏暂停弹出字体_小白写了个java的小游戏 想加个暂停的功能 无从下手 求大佬们帮...
  6. python中打乱顺序的函数_numpy.random.shuffle打乱顺序函数的实现
  7. WIN10找不到服务器共享文件,win10没有共享选项怎么办_win10文件属性没有共享选项的解决方法...
  8. linux用户一个用户只能一个用户组,为什么linux用户可以属于多个用户组,文件只能属于一个用户组?...
  9. packagereference 里面的资产是怎么回事?
  10. shift键计算机功能,电脑shift键常用快捷键使用攻略
  11. 监控里的主码流和子码流是什么意思
  12. Cadence 导出变种BOM详细操作方法
  13. 【2058】简单计算器
  14. CSS面试须知--盒子模型、浮动及定位
  15. 2019年内大892数据结构部分参考答案
  16. Matlab绘制特殊图形------直方图
  17. 通信原理-第9章-数字信号的最佳接收
  18. 迷宫游戏(wap页游还原)-JavaScript实现
  19. python machine learning_Python Machine Learning
  20. 易语言制作计算软件简单步骤_视频解说不想自己录,用什么简单好用的配音软件制作?...

热门文章

  1. 嵌入式工程师16个问题
  2. 4片74151扩展为32选1数据选择器
  3. CTF-RSA_基于N分解的RSA题目
  4. 测试开发工作者日记【终焉】:再见~ 小猪
  5. Jupyter离线安装部署
  6. springboot电竞俱乐部推荐系统
  7. 【labview教程02】labview的前世今生
  8. Promox VE安装黑群晖保姆级图文教程
  9. 智能合约安全(一):以太坊机制及安全问题
  10. DirectX (9) 纹理映射