目录
- 剑指Offer-03 数组中重复的数字
- 剑指Offer-04 二维数组中的查找
- 剑指Offer-05 替换空格
- 剑指Offer-06 从尾到头打印链表
- 剑指Offer-07 重建二叉树
- 剑指Offer-09 用两个栈实现队列
- 剑指Offer-10-I 斐波那契数列
- 剑指Offer-10-II 青蛙跳台阶问题
- 剑指Offer-11 旋转数组的最小数字
- 剑指Offer-12 矩阵中的路径
- 剑指Offer-13 机器人的运动范围
- 剑指Offer-14-I 剪绳子
- 剑指Offer-14-II 剪绳子II
- 剑指Offer-15 二进制中1的个数
- 剑指Offer-16 数值的整数次方
- 剑指Offer-17 打印从1到最大的n位数
- 剑指Offer-18 删除链表的节点
- 剑指Offer-19 正则表达式匹配
- 剑指Offer-20 表示数值的字符串
- 剑指Offer-21 调整数组顺序使奇数位于偶数前面
- 剑指Offer-22 链表中倒数第k个节点
- 剑指Offer-24 反转链表
- 剑指Offer-25 合并两个排序的链表
- 剑指Offer-26 树的子结构
- 剑指Offer-27 二叉树的镜像
- 剑指Offer-28 对称的二叉树
- 剑指Offer-29 顺时针打印矩阵
- 剑指Offer-30 包含min函数的栈
- 剑指Offer-31 栈的压入、弹出序列
- 剑指Offer-32-I 从上到下打印二叉树
- 剑指Offer-32-II 从上到下打印二叉树II
- 剑指Offer-32-III 从上到下打印二叉树III
- 剑指Offer-33 二叉搜索树的后序遍历序列
- 剑指Offer-34 二叉树中和为某一值的路径
- 剑指Offer-35 复杂链表的复制
- 剑指Offer-36 二叉搜索树与双向链表
- 剑指Offer-37 序列化二叉树
- 剑指Offer-38 字符串的排列
- 剑指Offer-39 数组中出现次数超过一半的数字
- 剑指Offer-40 最小的k个数
- 剑指Offer-41 数据流中的中位数
- 剑指Offer-42 连续子数组的最大和
- 剑指Offer-43 1~n整数中1出现的次数
- 剑指Offer-44 数字序列中某一位的数字
- 剑指Offer-45 把数组排成最小的数
- 剑指Offer-46 把数字翻译成字符串
- 剑指Offer-47 礼物的最大价值
- 剑指Offer-48 最长不含重复字符的子字符串
- 剑指Offer-49 丑数
- 剑指Offer-50 第一个只出现一次的字符
- 剑指Offer-51 数组中的逆序对
- 剑指Offer-52 两个链表的第一个公共节点
- 剑指Offer-53-I 在排序数组中查找数字I
- 剑指Offer-53-II 0~n-1中缺失的数字
- 剑指Offer-54 二叉搜索树的第k大节点
- 剑指Offer-55-I 二叉树的深度
- 剑指Offer-55-II 平衡二叉树
- 剑指Offer-56-I 数组中数字出现的次数
- 剑指Offer-56-II 数组中数字出现的次数II
- 剑指Offer-57 和为s的两个数字
- 剑指Offer-57-II 和为s的连续正数序列
- 剑指Offer-58-I 翻转单词顺序
- 剑指Offer-58-II 左旋转字符串
- 剑指Offer-59-I 滑动窗口的最大值
- 剑指Offer-59-II 队列的最大值
- 剑指Offer-60 n个骰子的点数
- 剑指Offer-61 扑克牌中的顺子
- 剑指Offer-62 圆圈中最后剩下的数字
- 剑指Offer-63 股票的最大利润
- 剑指Offer-64 求1+2+…+n
- 剑指Offer-65 不用加减乘除做加法
- 剑指Offer-66 构建乘积数组
- 剑指Offer-67 把字符串转换成整数
- 剑指Offer-68-I 二叉搜索树的最近公共祖先
- 剑指Offer-68-II 二叉树的最近公共祖先
剑指Offer-03 数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内,数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:
2 或 3
代码a
class Solution {
public:
int findRepeatNumber(vector<int>& a) {
int n=a.size();
if(!n) return -1;
for(int i=0;i<n;i++)
{
while(a[i]!=a[a[i]])
swap(a[i],a[a[i]]);
if(i!=a[i]) return a[i];
}
return -1;
}
};
代码b
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
int c[100010]={0};
for(auto e:nums)
c[e]++;
for(int i=0;i<nums.size();i++)
if(c[i]>1)
return i;
return 0;
}
};
剑指Offer-04 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& a, int target) {
if(a.empty()) return 0;
int i=0,j=a[0].size()-1;
while(i<a.size()&&j>=0)
{
if(a[i][j]==target) return 1;
if(a[i][j]>target) j--;
else i++;
}
return 0;
}
};
剑指Offer-05 替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”
class Solution {
public:
string replaceSpace(string s) {
string res;
for(auto ch:s)
if(ch==' ')
res+="%20";
else
res+=ch;
return res;
}
};
剑指Offer-06 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
vector<int> res;
while(head)
{
res.push_back(head->val);
head=head->next;
}
for(int i=0,j=res.size()-1;i<j;i++,j--)
swap(res[i],res[j]);
return res;
}
};
剑指Offer-07 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
class Solution {
public:
unordered_map<int,int> pos;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
for (int i = 0; i < n; i ++ )
pos[inorder[i]] = i;
return dfs(preorder, inorder, 0, n - 1, 0, n - 1);
}
TreeNode* dfs(vector<int>&pre, vector<int>&in, int pl, int pr, int il, int ir)
{
if (pl > pr) return NULL;
int k = pos[pre[pl]] - il;
TreeNode* root = new TreeNode(pre[pl]);
root->left = dfs(pre, in, pl + 1, pl + k, il, il + k - 1);
root->right = dfs(pre, in, pl + k + 1, pr, il + k + 1, ir);
return root;
}
};
剑指Offer-09 用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
输入:
[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[3],[],[]]
输出:
[null,null,3,-1]
class CQueue {
public:
stack<int> A,B;
CQueue() {}
void appendTail(int value) {
A.push(value);
}
int deleteHead() {
if(B.size())
{
int t=B.top();
B.pop();
return t;
}
if(A.empty()) return -1;
while(A.size())
{
int t=A.top(); A.pop();
B.push(t);
}
int t=B.top();
B.pop();
return t;
}
};
/**
* Your CQueue object will be instantiated and called as such:
* CQueue* obj = new CQueue();
* obj->appendTail(value);
* int param_2 = obj->deleteHead();
*/
剑指Offer-10-I 斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
代码a
class Solution {
public:
int fib(int n) {
int a[110];a[0]=0,a[1]=1;
const int mod=1e9+7;
for(int i=2;i<105;i++)
a[i]=(a[i-1]+a[i-2])%mod;
return a[n];
}
};
代码b
class Solution {
public:
int fib(int n) {
if(n<2) return n;
const int mod=1e9+7;
int a=0,b=1,c;
for(int i=2;i<=n;i++)
{
c=(a+b)%mod;
a=b;
b=c;
}
return b;
}
};
剑指Offer-10-II 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
示例 3:
输入:n = 0
输出:1
提示:
0 <= n <= 100
class Solution {
public:
int numWays(int n) {
const int mod=1e9+7;
int a=1,b=1,c;
for(int i=0;i<n;i++)
{
c=(a+b)%mod;
a=b;
b=c;
}
return a;
}
};
剑指Offer-11 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
class Solution {
public:
int minArray(vector<int>& nums) {
int n = nums.size() - 1;
if (n < 0) return -1;
while (n > 0 && nums[n] == nums[0]) n -- ;
if (nums[n] >= nums[0]) return nums[0];
int l = 0, r = n;
while (l < r) {
int mid = l + r >> 1; // [l, mid], [mid + 1, r]
if (nums[mid] < nums[0]) r = mid;
else l = mid + 1;
}
return nums[r];
}
};
剑指Offer-12 矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
示例 1:
输入:
board =
[[“A”,“B”,“C”,“E”],
[“S”,“F”,“C”,“S”],
[“A”,“D”,“E”,“E”]],
word = “ABCCED”
输出:true
示例 2:
输入:
board =
[[“a”,“b”],
[“c”,“d”]],
word = “abcd”
输出:false
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
class Solution {
public:
bool exist(vector<vector<char>>& a, string &str) {
for(int i=0;i<a.size();i++)
for(int j=0;j<a[i].size();j++)
if(dfs(a,str,0,i,j))
return true;
return false;
}
bool dfs(vector<vector<char>>& a,string &str,int u,int x,int y)
{
if(a[x][y]!=str[u]) return false;
if(u==str.size()-1) return true;
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
char ch=a[x][y];
a[x][y]='+';
for(int i=0;i<4;i++)
{
int xx=x+dx[i],yy=y+dy[i];
if(xx>=0 && xx<a.size() && yy>=0 && yy<a[0].size())
if(dfs(a,str,u+1,xx,yy))
return true;
}
a[x][y]=ch;
return false;
}
};
剑指Offer-13 机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
class Solution {
public:
int f(int x)
{
int s=0;
while(x) s+=x%10,x/=10;
return s;
}
int get_sum(pair<int,int> t)
{
return f(t.first)+f(t.second);
}
int movingCount(int threshold, int rows, int cols)
{
if(!rows || !cols) return 0;
queue<pair<int,int>> q;
vector<vector<bool>> st(rows,vector<bool> (cols));
int dx[4]={0,0,1,-1},dy[4]={-1,1,0,0};
int res=0;
q.push({0,0});
while(q.size())
{
auto t=q.front();q.pop();
if(st[t.first][t.second] || get_sum(t)>threshold) continue;
res++;
st[t.first][t.second]=true;
for(int i=0;i<4;i++)
{
int x=t.first+dx[i],y=t.second+dy[i];
if(x<0 ||x>=rows ||y<0 ||y>=cols) continue;
q.push({x,y});
}
}
return res;
}
};
剑指Offer-14-I 剪绳子
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 58
class Solution {
public:
int cuttingRope(int n) {
if(n==2) return 1;
if(n==3) return 2;
int res=1;
if(n%3==1) res*=4,n-=4;
if(n%3==2) res*=2,n-=2;
while(n) res*=3,n-=3;
return res;
}
};
剑指Offer-14-II 剪绳子II
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1] 。请问 k[0]k[1]…*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 1000
class Solution {
public:
int cuttingRope(int n) {
if(n <= 3) return n - 1;
long res=1L;
int p=(int)1e9+7; //贪心算法,优先切三,其次切二
while(n>4){
res=res*3%p;
n-=3;
} //出来循环只有三种情况,分别是n=2、3、4
return (int)(res*n%p);
}
};
剑指Offer-15 二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。
class Solution {
public:
int hammingWeight(uint32_t n) {
unsigned int c=0;
while(n)
{
c+=n&1;
n>>=1;
}
return c;
}
};
剑指Offer-16 数值的整数次方
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入: 2.00000, 10
输出: 1024.00000
示例 2:
输入: 2.10000, 3
输出: 9.26100
示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
class Solution {
public:
double myPow(double x, int _n) {
double res=1;
long n=_n;
bool op=0;
if(n<0) op=1,n=-n;
while(n)
{
if(n&1) res*=x;
x*=x;
n>>=1;
}
if(op) res=1/res;
return res;
}
};
剑指Offer-17 打印从1到最大的n位数
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
说明:
用返回一个整数列表来代替打印
n 为正整数
class Solution {
public:
vector<int> printNumbers(int n) {
vector<int> res;
int len=pow(10,n);
for(int i=1;i<len;i++)
res.push_back(i);
return res;
}
};
剑指Offer-18 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动
示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
题目保证链表中节点的值互不相同
若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
auto dummy=new ListNode(-1);
dummy->next=head;
auto pre=dummy;
while(head)
{
if(head->val ==val) break;
head=head->next;
pre=pre->next;
}
pre->next=head->next;
return dummy->next;
}
};
剑指Offer-19 正则表达式匹配
请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’‘表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"aba"均不匹配。
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = "a"
输出: true
解释: 因为 ‘’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:
输入:
s = “ab”
p = "."
输出: true
解释: "." 表示可匹配零个或多个(’’)任意字符(’.’)。
示例 4:
输入:
s = “aab”
p = “cab”
输出: true
解释: 因为 ‘’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:
s = “mississippi”
p = "misisp."
输出: false
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 ,无连续的 '’。
class Solution {
public:
bool isMatch(string s, string p) {
int n = s.size(), m = p.size();
s = ' ' + s, p = ' ' + p;
vector<vector<bool>> f(n + 1, vector<bool>(m + 1));
f[0][0] = true;
for (int i = 0; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
if (j + 1 < p.size() && p[j + 1] == '*') continue;
if (i && p[j] != '*')
{
f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
}
else if (p[j] == '*')
{
f[i][j] = f[i][j - 2] || i && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.');
}
}
return f[n][m];
}
};
剑指Offer-20 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、“5e2”、"-123"、“3.1416”、"-1E-16"、“0123"都表示数值,但"12e”、“1a3.14”、“1.2.3”、"±5"及"12e+5.4"都不是。
代码a
class Solution {
public:
bool isNumber(string s) {
int i = 0;
while (i < s.size() && s[i] == ' ') i ++ ;
int j = s.size() - 1;
while (j >= 0 && s[j] == ' ') j -- ;
if (i > j) return false;
s = s.substr(i, j - i + 1);
if (s[0] == '-' || s[0] == '+') s = s.substr(1);
if (s.empty() || s[0] == '.' && s.size() == 1) return false;
int dot = 0, e = 0;
for (int i = 0; i < s.size(); i ++ )
{
if (s[i] >= '0' && s[i] <= '9');
else if (s[i] == '.')
{
dot ++ ;
if (e || dot > 1) return false;
}
else if (s[i] == 'e' || s[i] == 'E')
{
e ++ ;
if (i + 1 == s.size() || !i || e > 1 || i == 1 && s[0] == '.') return false;
if (s[i + 1] == '+' || s[i + 1] == '-')
{
if (i + 2 == s.size()) return false;
i ++ ;
}
}
else return false;
}
return true;
}
};
代码b
class Solution(object):
def isNumber(self, s):
try:
float(s)
return True;
except:
return False;
剑指Offer-21 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
示例:
输入: nums= [1,2,3,4]
输出: [1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
class Solution {
public:
vector<int> exchange(vector<int>& a) {
int i=0,j=a.size()-1;
while(i<j)
{
while(i<j && a[i]%2==1) i++;
while(i<j && a[j]%2==0) j--;
swap(a[i],a[j]);
}
return a;
}
};
剑指Offer-22 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
示例:
给定一个链表: 1->2->3->4->5 和 k = 2.
返回链表: 4->5.
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
auto i=head,j=head;
while(k--) j=j->next;
while(j) i=i->next,j=j->next;
return i;
}
};
剑指Offer-24 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。 示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
用cur表示head后 循环中就不需要在出现head
class Solution {
public:
ListNode* reverseList(ListNode* head) {
auto cur=head;
ListNode* pre=nullptr;
while(cur)
{
auto ne=cur->next;
cur->next=pre;
pre=cur;
cur=ne;
}
return pre;
}
};
剑指Offer-25 合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
auto dummy=new ListNode(-1);
auto cur=dummy; //cur指向当前的尾结点
while(l1 && l2)
{
if(l1->val<l2->val)
{
cur->next=l1;
cur=l1;
l1=l1->next;
}
else
{
cur->next=l2;
cur=l2;
l2=l2->next;
}
}
if(l1) cur->next=l1;
else cur->next=l2;
return dummy->next;
}
};
剑指Offer-26 树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:3 / \ 4 5 / \ 1 2
给定的树 B:
4 / 1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例 1:
输入:A = [1,2,3], B = [3,1] 输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1] 输出:true
class Solution {
public:
bool isSubStructure(TreeNode* s, TreeNode* p) {
if(!s || !p) return false;
if(isPart(s,p)) return true;
return isSubStructure(s->left,p) ||isSubStructure(s->right,p);
}
bool isPart(TreeNode* s, TreeNode* p)
{
if(!p) return true;
if(!s || s->val!=p->val) return false;
return isPart(s->left,p->left) && isPart(s->right,p->right);
}
};
剑指Offer-27 二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4 / \ 2 7 / \ / \ 1 3 6 9
镜像输出:
4 / \ 7 2 / \ / \ 9 6 3 1
示例 1:
输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(!root) return 0;
mirrorTree(root->left);
mirrorTree(root->right); swap(root->left,root->right);
return root;
}
};
剑指Offer-28 对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1 / \ 2 2 / \ / \ 3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1 / \ 2 2 \ \ 3 3
示例 1:
输入:root = [1,2,2,3,4,4,3] 输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3] 输出:false
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(!root) return true;
return dfs(root->left,root->right);
}
bool dfs(TreeNode* p,TreeNode* q)
{
if(!p || !q) return !p&&!q; //只要有一个为空,就返回 是否同时为空
if(p->val != q->val) return false;
return dfs(p->left,q->right) && dfs(p->right,q->left);
}
};
剑指Offer-29 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:
matrix = [[1,2,3], [4,5,6], [7,8,9]]
输出:
[1,2,3,6,9,8,7,4,5]
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& a) {
vector<int> res;
if(a.empty()) return res;
int l=0,r=a[0].size()-1,t=0,d=a.size()-1;
while(true)
{
for(int i=l;i<=r;i++) res.push_back(a[t][i]);
if(++t > d) break;
for(int i=t;i<=d;i++) res.push_back(a[i][r]);
if(l > --r) break;
for(int i=r;i>=l;i--) res.push_back(a[d][i]);
if(t > --d) break;
for(int i=d;i>=t;i--) res.push_back(a[i][l]);
if(++l > r) break;
}
return res;
}
};
剑指Offer-30 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是
O(1)。
示例:MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.min(); --> 返回 -3. minStack.pop(); minStack.top(); --> 返回 0. minStack.min(); --> 返回 -2.
class MinStack {
public:
/** initialize your data structure here. */
MinStack() {}
stack<int> A,B;
void push(int x) {
A.push(x);
if(B.empty() || x<=B.top())
B.push(x);
}
void pop() {
if(A.top()==B.top()) B.pop();
A.pop();
}
int top() {
return A.top();
}
int min() {
return B.top();
}
};
剑指Offer-31 栈的压入、弹出序列
class Solution {
public:
bool validateStackSequences(vector<int>& a, vector<int>& b)
{
if(a.size()!=b.size()) return false;
stack<int> stk;
int i=0;
for(auto x: a)
{
stk.push(x);
while(stk.size() && stk.top()==b[i])
{
stk.pop();
i++;
}
}
return stk.empty();
}
};
剑指Offer-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) return res;
queue<TreeNode*> q;
q.push(root);
while(q.size())
{
auto t=q.front();q.pop();
res.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
return res;
}
};
剑指Offer-32-II 从上到下打印二叉树II
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root) return res;
queue<TreeNode*> q;
vector<int> level;
q.push(root);
q.push(nullptr);
while(q.size())
{
auto t=q.front();
q.pop();
if(t)
{
level.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
continue;
}
if(level.empty()) break;
res.push_back(level);
level.clear();
q.push(nullptr);
}
return res;
}
};
剑指Offer-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;
if(!root) return res;
queue<TreeNode*> q;
q.push(root);
q.push(nullptr);
vector<int> level;
bool st=false;
while(q.size())
{
auto t=q.front();
q.pop();
if(t)
{
level.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
continue;
}
if(level.empty()) break;
if(st) reverse(level.begin(),level.end());
st=!st;
res.push_back(level);
level.clear();
q.push(nullptr);
}
return res;
}
};
剑指Offer-33 二叉搜索树的后序遍历序列
class Solution {
public:
vector<int> seq;
bool verifyPostorder(vector<int> sequence) {
seq=sequence;
return dfs(0,seq.size()-1);
}
bool dfs(int l,int r)
{
if(l>=r) return true;
int root=seq[r];
int k=l;
while(l<r && seq[k]<root) k++;
for(int i=k;i<r;i++)
if(seq[i]<root)
return false;
return dfs(l,k-1) && dfs(k,r-1);
}
};
剑指Offer-34 二叉树中和为某一值的路径
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> pathSum(TreeNode* root, int sum) {
dfs(root,sum);
return res;
}
void dfs(TreeNode* root,int sum)
{
if(!root) return ;
path.push_back(root->val);
sum-=root->val;
if(!root->left && !root->right && !sum) res.push_back(path);
dfs(root->left,sum);
dfs(root->right,sum);
path.pop_back();
}
};
剑指Offer-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 {
public:
Node* copyRandomList(Node* head) {
if(head==NULL) return head;
unordered_map<Node*,Node*>mp;
Node *t=head;
while(t!=NULL){
mp[t]=new Node(t->val);
t=t->next;
}
t=head;
while(t!=NULL){
if(t->next){
mp[t]->next=mp[t->next];
}
if(t->random){
mp[t]->random=mp[t->random];
}
t=t->next;
}
return mp[head];
}
};
剑指Offer-36 二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
class Solution {
public:
Node* treeToDoublyList(Node* root) {
if (!root ) return NULL;
// vector中保存了中序遍历的结果
vector<Node*> nodes;
inorderTraverse(root, nodes);
int n = nodes.size();
for (int i = 0; i < n; i++) {
// (i + n - 1) % n 避免第一个结点的index 0 减1出现负数
nodes[i]->left = nodes[(i + n - 1) % n];
// (i + 1) % n 是为了避免最后一个结点 + 1越界
nodes[i]->right = nodes[(i + 1) % n];
}
return nodes[0];
}
void inorderTraverse(Node *root, vector<Node *> &nodes) {
if (!root ) return;
inorderTraverse(root->left, nodes);
nodes.push_back(root);
inorderTraverse(root->right, nodes);
}
};
剑指Offer-37 序列化二叉树
class Codec {
public:
string str;
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if(!root) // 空树的情况
{
str += "null ";
return str;
}
queue<TreeNode*> q;
q.push(root);
while(q.size())
{
auto node = q.front();
q.pop();
if(node == nullptr) str += "null ";
else
{
str += (to_string(node->val) + ' ');
q.push(node->left);
q.push(node->right);
}
}
return str;
}
int getval(string& data, int cur, int next)
{
int val = 0;
if(data[cur] != '-')
for(int i = cur; i < next; ++i) val = val * 10 + data[i] - '0';
else
{
for(int i = cur + 1; i < next; ++i) val = val * 10 + data[i] - '0';
val = -val;
}
return val;
}
// Decodes your encoded data to tree.
// 思路:使用队列,从根节点开始,层层去构建二叉树的结点。
TreeNode* deserialize(string data) {
// 1. 先构建根节点
queue<TreeNode*> q;
auto root = new TreeNode(-1);
int cur = 0, next = 0;
while(next < data.size() && data[next] != ' ') next++;
// 此时 next 是第一个空格的位置
if(data[cur] == 'n') return nullptr;
else
{
int val = getval(data, cur, next);
root->val = val;
q.push(root);
}
// 2. 使用队列逐步向下一层扩展(bfs)
cur = next + 1;
next = cur;
while(q.size())
{
auto node = q.front();
q.pop();
if(node == nullptr) continue;
// 解析左节点,解析后链接
TreeNode* left = nullptr;
while(next < data.size() && data[next] != ' ') next++;
if(data[cur] != 'n')
{
int val = getval(data, cur, next);
left = new TreeNode(val);
}
node->left = left;
q.push(left);
cur = next + 1;
next = cur;
// 解析右结点,解析后链接
TreeNode* right = nullptr;
while(next < data.size() && data[next] != ' ') next++;
if(data[cur] != 'n')
{
int val = getval(data, cur, next);
right = new TreeNode(val);
}
node->right = right;
q.push(right);
cur = next + 1;
next = cur;
}
return root;
}
};
剑指Offer-38 字符串的排列
class Solution {
public:
vector<string> res;
string s,ans;
bool st[10];
vector<string> permutation(string _s) {
s=_s;
dfs(s.size(),0);
sort(res.begin(),res.end());
res.erase(unique(res.begin(),res.end()),res.end());
return res;
}
void dfs(int n,int k)
{
if(k==n)
{
res.push_back(ans);
return ;
}
for(int i=0;i<n;i++)
{
if(st[i]) continue;
st[i]=true;
ans.push_back(s[i]);
dfs(n,k+1);
st[i]=false;
ans.pop_back();
}
}
};
剑指Offer-39 数组中出现次数超过一半的数字
class Solution {
public:
int majorityElement(vector<int>& nums) {
int val=nums[0],cnt=1;
for(int i=1;i<nums.size();i++)
{
if(nums[i] == val) cnt++;
else cnt--;
if(cnt==0)
{
val=nums[i];
cnt=1;
}
}
return val;
}
};
剑指Offer-40 最小的k个数
class Solution {
public:
vector<int> getLeastNumbers(vector<int> input, int k) {
priority_queue<int> heap;
vector<int> res;
for(int x:input)
{
heap.push(x);
if(heap.size()>k) heap.pop();
}
while(heap.size()) res.push_back(heap.top()),heap.pop();
reverse(res.begin(),res.end());
return res;
}
};
剑指Offer-41 数据流中的中位数
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {}
priority_queue<int,vector<int>,greater<int>> A;//小根堆
priority_queue<int> B;//大根堆
void addNum(int num) {
B.push(num);
if(A.size() && A.top() < B.top())
{
int maxv=B.top(),minv=A.top();
A.pop(),B.pop();
A.push(maxv),B.push(minv);
}
if(B.size() > A.size()+1)
{
A.push(B.top());
B.pop();
}
}
double findMedian() {
if(A.size()+B.size() &1) return B.top();
return (A.top()+B.top())/2.0;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
剑指Offer-42 连续子数组的最大和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int res=INT_MIN,s=0;
for(auto e:nums)
{
if(s>0) s+=e;
else s=e;
res=max(res,s);
}
return res;
}
};
剑指Offer-43 1~n整数中1出现的次数
class Solution {
public:
int countDigitOne(int n) {
vector<int> a;
while(n)
{
a.push_back(n%10);
n/=10;
}
int res=0;
for(int i=a.size()-1;i>=0;i--)
{
int left=0,right=0,t=1;
for(int j=a.size()-1;j>i;j--) left=left*10+a[j];
for(int j=i-1;j>=0;j--) right=right*10+a[j],t*=10;
res+=left*t;
if(a[i]==1) res+=right+1;
if(a[i]>1) res+=t;
}
return res;
}
};
剑指Offer-44 数字序列中某一位的数字
class Solution {
public:
int findNthDigit(int n) {
long long i = 1, s = 9, base = 1;
//i表示是几位数,s表示位数共有多少个,base表示位数的起始值。
while(n > i * s)
{
// 9, 90, 900, 9000, 90000, i * s表示位数总共占多少位。
n -= i * s;// 1000 - 9 - 90 * 2 - 900 * 3 ,当i= 3 时不符合条件,说明是在三位数里面。
i ++;
s *= 10;
base *= 10;
}
int number = base + (n + i - 1) / i - 1; //求位数的第几个数, 1000 - 9 - 180 = n , n / 3 + base - 1(考虑0故减1), 向上取整 n + i - 1。
int r = n % i ? n % i : i; // 除不尽就是第几位,除尽力了就是最后一位。
for (int j = 0; j < i - r; j ++) number /= 10; //求数的第i - r位,取出第i - r位。
return number % 10;
}
};
剑指Offer-45 把数组排成最小的数
bool cmp(string &a,string &b)
{
return a+b<b+a;
}
class Solution {
public:
string minNumber(vector<int>& nums) {
vector<string> str;
for (int i = 0; i < nums.size(); i++)
str.push_back(to_string(nums[i]));
sort(str.begin(), str.end(), cmp);
//sort(str.begin(), str.end(), [](string& s1, string& s2){return s1 + s2 < s2 + s1;});
string res;
for (int i = 0; i < str.size(); i++)
res += str[i];
return res;
}
};
剑指Offer-46 把数字翻译成字符串
class Solution {
public:
int translateNum(int num) {
string s = to_string(num);
int a=1,b=1;
for(int i=2;i<=s.size();i++)
{
string t = s.substr(i-2,2);
int c = stoi(t)>=10 && stoi(t)<=25 ? a+b:a;
b=a;
a=c;
}
return a;
}
};
剑指Offer-47 礼物的最大价值
class Solution {
public:
int maxValue(vector<vector<int>>& a) {
int n=a.size(),m=a[0].size();
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(i==0 && j==0) continue;
else if(i==0) a[i][j]+=a[i][j-1];
else if(j==0) a[i][j]+=a[i-1][j];
else a[i][j]+=max(a[i-1][j],a[i][j-1]);
}
return a[n-1][m-1];
}
};
剑指Offer-48 最长不含重复字符的子字符串
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char,int> hash;
int i=-1,res=0;
for(int j=0;j<s.size();j++)
{
if(hash.find(s[j])!=hash.end()) i=max(i,hash[s[j]]);
hash[s[j]]=j;
res=max(res,j-i);
}
return res;
}
};
剑指Offer-49 丑数
class Solution {
public:
int nthUglyNumber(int n) {
if(n <= 1) return n;
vector<int> f(1,1);
int i = 0, j = 0, k = 0;
long long t = 0;
while(--n)
{
t = min(f[i] * 2, min (f[j] * 3, f[k] * 5));
if(t == f[i] * 2) i++;
if(t == f[j] * 3) j++;
if(t == f[k] * 5) k++;
f.push_back(t);
}
return f.back();
}
};
剑指Offer-50 第一个只出现一次的字符
class Solution {
public:
char firstUniqChar(string s) {
unordered_map<char,int> cnt;
for(auto ch:s)
cnt[ch]++;
for(auto ch:s)
if(cnt[ch]==1)
return ch;
return ' ';
}
};
剑指Offer-51 数组中的逆序对
class Solution {
public:
int res;
int tmp[50010];
void merge_sort(vector<int>&a,int l,int r)
{
if(l>=r) return ;
int mid= l+r >>1;
merge_sort(a,l,mid);
merge_sort(a,mid+1,r);
int i=l,j=mid+1,k=0;
while(i<=mid&&j<=r)
if(a[i]<=a[j])
tmp[k++]=a[i++];
else
tmp[k++]=a[j++],res+=mid-i+1;
while(i<=mid)
tmp[k++]=a[i++];
while(j<=r)
tmp[k++]=a[j++];
for(i=l,j=0;i<=r;i++,j++)
a[i]=tmp[j];
}
int reversePairs(vector<int>& nums) {
merge_sort(nums,0,nums.size()-1);
return res;
}
};
剑指Offer-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) {
auto p=headA,q=headB;
while(q!=p)
{
if(p) p=p->next;
else p=headB;
if(q) q=q->next;
else q=headA;
}
return q;
}
};
剑指Offer-53-I 在排序数组中查找数字I
class Solution {
public:
int search(vector<int>& nums, int target) {
int c=0;
for(auto e:nums)
if(e==target) c++;
return c;
}
};
剑指Offer-53-II 0~n-1中缺失的数字
class Solution {
public:
int missingNumber(vector<int>& a) {
for(int i=0;i<a.size();i++)
{
while(i!=a[i] && a[i]<a.size()) swap(a[i],a[a[i]]);
if(i!=a[i]) return i;
}
return a.size();
}
};
剑指Offer-54 二叉搜索树的第k大节点
class Solution {
public:
vector<int> v;
int kthLargest(TreeNode* root, int k) {
inorder(root);
return v[v.size()-k];
}
void inorder(TreeNode* root)
{
if(!root) return;
inorder(root->left);
v.push_back(root->val);
inorder(root->right);
}
};
剑指Offer-55-I 二叉树的深度
class Solution {
public:
int maxDepth(TreeNode* root) {
if(!root) return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
剑指Offer-55-II 平衡二叉树
class Solution {
public:
bool res=true;
bool isBalanced(TreeNode* root) {
dfs(root);
return res;
}
int dfs(TreeNode* root)
{
if(!root) return 0;
int left=dfs(root->left),right=dfs(root->right);
if(abs(left-right)>1) res=false;
return max(left,right)+1;
}
};
剑指Offer-56-I 数组中数字出现的次数
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int sum=0;
for(auto x:nums) sum^=x;
int k=0,first=0;
while(!(sum>>k&1)) k++;
for(auto x:nums) x>>k&1?first^=x:x;
return vector<int>{first,sum^first};
}
};
剑指Offer-56-II 数组中数字出现的次数II
O(32n)近似为O(nlogn)
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res=0;
for(int i=0;i<32;i++)
{
int cnt=0;
for(int j=0;j<nums.size();j++)
{
if(nums[j]>>i&1) cnt++;
}
if(cnt%3) res+=(1<<i);
else res+=(0<<i);
}
return res;
}
};
严格上O(n):
class Solution {
public:
int singleNumber(vector<int>& nums) {
int one=0,two=0;
for(auto x:nums)
{
one=(one^x) & ~two;
two=(two^x) & ~one;
}
return one;
}
};
剑指Offer-57 和为s的两个数字
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int i=0,j=nums.size()-1;
while(i<j)
{
if(nums[i] == target-nums[j]) return {nums[i],nums[j]};
if(nums[i] < target-nums[j]) i++;
else j--;
}
return {};
}
};
剑指Offer-57-II 和为s的连续正数序列
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>> res;
int i = 1; // 滑动窗口的左边界
int j = 1; // 滑动窗口的右边界
int sum = 0; // 滑动窗口中数字的和
while (i <= target / 2)
{
if (sum < target)
{
sum += j; // 右边界向右移动
j++;
}
else if (sum > target)
{
sum -= i; // 左边界向右移动
i++;
}
else
{
vector<int> arr; // 记录结果
for (int k = i; k < j; k++)
{
arr.push_back(k);
}
res.push_back(arr);
sum -= i; // 左边界向右移动
i++;
}
}
return res;
}
};
剑指Offer-58-I 翻转单词顺序
class Solution {
public:
string reverseWords(string s) {
stringstream in(s);
string res,temp;
while(in>>temp)
{
res=temp+" "+res;
}
res.pop_back();
return res;
}
};
剑指Offer-58-II 左旋转字符串
class Solution {
public:
string reverseLeftWords(string s, int n) {
return s.substr(n)+s.substr(0,n);
}
};
剑指Offer-59-I 滑动窗口的最大值
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& a, int k) {
vector<int> res;
deque<int> q;
for(int i=0;i<a.size();i++)
{
if(q.size() && q.front()<i-k+1) q.pop_front();
while(q.size() && a[q.back()]<a[i]) q.pop_back();
q.push_back(i);
if(i>=k-1) res.push_back(a[q.front()]);
}
return res;
}
};
剑指Offer-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;
}
int pop_front() {
if (begin == end)
return -1;
return q[begin++];
}
};
剑指Offer-60 n个骰子的点数
class Solution {
public:
vector<double> dicesProbability(int n) {
int dp[15][70];
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= 6; i ++)
dp[1][i] = 1;
for (int i = 2; i <= n; i ++) {
for (int j = i; j <= 6*i; j ++) {
for (int cur = 1; cur <= 6; cur ++) {
if (j - cur <= 0) {
break;
}
dp[i][j] += dp[i-1][j-cur];
}
}
}
int all = pow(6, n);
vector<double> res;
for (int i = n; i <= 6 * n; i ++) {
res.push_back(dp[n][i] * 1.0 / all);
}
return res;
}
};
剑指Offer-61 扑克牌中的顺子
class Solution {
public:
bool isStraight(vector<int>& nums) {
sort(nums.begin(),nums.end());
int k=0;
while(!nums[k]) k++;
for(int i=k+1;i<nums.size();i++)
if(nums[i]==nums[i-1]) return false;
return nums[4]-nums[k] < 5;
}
};
剑指Offer-62 圆圈中最后剩下的数字
class Solution {
public:
int lastRemaining(int n, int m) {
if (n == 1) return 0;
int x = lastRemaining(n - 1, m);
return (m + x) % n;
}
};
剑指Offer-63 股票的最大利润
class Solution {
public:
int maxProfit(vector<int>& a) {
int res=0;
for(auto t:a)
{
int cost=min(cost,t);
res=max(res,t-cost);
}
return res;
}
};
剑指Offer-64 求1+2+…+n
class Solution {
public:
int sumNums(int n) {
char a[n][n+1];
return sizeof (a)>>1;
}
};
剑指Offer-65 不用加减乘除做加法
class Solution {
public:
int add(int a, int b) {
while(b)
{
int c=(unsigned int) (a&b)<<1;
a^=b;
b=c;
}
return a;
}
};
剑指Offer-66 构建乘积数组
class Solution {
public:
vector<int> constructArr(vector<int>& a) {
int len = a.size();
vector<int> b(len, 1);
if(len == 0) return b;
int left = 1, right = 1;
for(int i = 0; i < len; i++)
{
b[i] *= left;
left *= a[i]; // 持有左边的所有数的乘积
b[len - i - 1] *= right;
right *= a[len -i - 1]; // 持有右边的所有数的乘积
}
return b;
}
};
剑指Offer-67 把字符串转换成整数
class Solution {
public:
int strToInt(string str) {
int i = 0, flag = 1;
long res = 0; //默认flag = 1,正数
while (str[i] == ' ') i ++;
if (str[i] == '-') flag = -1;
if (str[i] == '-' || str[i] == '+') i ++;
for (; i < str.size() && isdigit(str[i]); i ++) {
res = res * 10 + (str[i] - '0');
if (res >= INT_MAX && flag == 1) return INT_MAX;
if (res > INT_MAX && flag == -1) return INT_MIN;
}
return flag * res;
}
};
剑指Offer-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 {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root || root==p || root==q) return root;
auto left = lowestCommonAncestor(root->left,p,q);
auto right= lowestCommonAncestor(root->right,p,q);
return left==0 ? right : (right==0 ? left : root);
}
};
剑指Offer-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* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root || root==p || root==q) return root;
auto left = lowestCommonAncestor(root->left,p,q);
auto right= lowestCommonAncestor(root->right,p,q);
return left==0 ? right : (right==0 ? left : root);
}
};