《剑指 Offer(第 2 版)》系列刷题
Posted 陆嵩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《剑指 Offer(第 2 版)》系列刷题相关的知识,希望对你有一定的参考价值。
剑指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 [二叉树的最近公共祖先]
- 补充题
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剑指 Offer(第 2 版)刷题 | 05. 替换空格
剑指 Offer(第 2 版)刷题 | 04. 二维数组中的查找
剑指 Offer(第 2 版)刷题 | 03. 数组中重复的数字