- 题目概览数据来自leetcode,截止至2020.08;其实数据没有什么用,干就完了
- 另外我会对题目进行补充,因为这些题目的变种也常出现,题解思路与注意事项来自leetcode、csdn、简书;来源过多恕不能全部记录来源,请原作者看到后私信我🙏
- 代码全部为本人在leetcode上的AC代码,均添加了注释。
- 本文力求还原思维过程,使解题过程生动有逻辑,帮助大家更好地进行思考和面试
- 行文逻辑为:题目(>题干)>考察点>思路>复杂度
剑指 Offer 03 数组中重复的数字(三种要求)
这道题在原书上绝对不是简单级别啊!
它考察的是程序员的沟通能力,先问面试官要时间/空间需求!!!
只是时间优先,就用字典;
还有空间要求,就用原地置换;
如果面试官要求空间O(1)并且不能修改原数组,得写成二分法。
时间优先 字典解法
时间复杂度为 O(n)
,空间复杂度为 O(n)
对于 n
长数组中 [0, n]
范围的数字,从头遍历,将值为i的数字放到第i位,若此处已有数字i,代笔i重复。
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
bool flag[nums.size()]; //标志数组,表示数字i是否出现过
memset(flag, false, sizeof(flag)); //全部置false
for(int i = 0; i < nums.size(); i++)
if(flag[nums[i]]){
return nums[i]; //若某元素出现过,则返回该数字
}else{
flag[nums[i]] = true; //遍历并标注已出现
}
}
return -1; //若从未有重复出现的数字,则返回-1
}
};
空间O(1) 原地置换
时间复杂度为 O(n)
,空间复杂度为 O(1)
对于 n
长数组中 [0, n]
范围的数字,不能使用额外空间,就要将出现信息保存在本数组中,将数字的值作为索引,将数字放到自己的位置上,如果数字不重复,那么数组上同一个位置的数字不会出现两次。
我们在遍历数组时将数字进行交换归位,如果复位时某的数组位置已经有了一个值等于索引的元素,代表此处素组
class Solution {
public int findRepeatNumber(int[] nums) {
int temp;
for(int i=0;i<nums.length;i++){//
while (nums[i]!=i){//如果i位置不是i,则操作,直到是i
if(nums[i]==nums[nums[i]]){//如果i处数字已经有了一个放置好的,则重复了
return nums[i];
}
//交换两者
temp=nums[i];
nums[i]=nums[temp];
nums[temp]=temp;
}
}
return -1;
}
}
空间O(1)且不能修改数组 二分
时间复杂度为 O(nlogn)
,空间复杂度为 O(1)
- 代码:
//
采取二分思想,抽屉原理:
对于 n
长数组中 [0, n]
范围的数字,从头遍历,将值为i的数字放到第i位,若此处已有数字i,代笔i重复。
借鉴二分查找的思想,将数字1n拆分成1m和m+1n两部分,如果数字范围1m中数字个数大于m,则重复数字在1m中间,否则重复数字一定在数字范围m+1n中。基于二分查找法不能找到全部的重复数字,例如{2,2,3,3,4,5,6,7}中数字区间为1~2的范围内2出现两次,但1没有出现,不能确定是每个数字出现一个还是某个数字出现两次。
高明解法:
首先将数组一分为二,假设数组有8个元素。那么元素大小都在 0 ~ 7 之间。一分为二,如果没有重复,四个元素在 0 ~ 3 之间,四个在 4 ~ 7 之间。假设数组为arr[8] = {1, 0, 2, 3, 3, 4, 5, 6},统计0 ~ 3 之间的元素有5个, 统计 4 ~ 7 之间的元素有3个。说明,在 0 ~ 3 之间肯定有重复元素。接下来划分 0 ~ 3的5个元素{1, 0, 2, 3, 3}。 0 ~ 1 之间有两个元素, 2~3之间有三个元素。再划分2 ~ 3之间的元素,2有一个,3有两个,所以重复的是元素3。
#include <iostream>
#include <vector>
using namespace std;
class Solution{
public:
int duplication(vector<int> vec)
{
// 空数组
int length = vec.size();
if(vec.size() == 0)
return -1;
// 数字超界
for(int i =0;i<length;++i)
{
if(vec[i]<1 || vec[i]>length-1)
return -1;
}
// 定义数字范围
int begin = 1;
int end = length-1;
// 指定数字范围内的数字个数
while(begin<=end)
{
// 计算数字范围的中点
int mid = (begin + end)>>1;
// 统计指定数字范围内的数字个数
int count = countrange(vec,begin,mid,length);
if(end > begin)
{
// 更新数字范围
if(count>(mid - begin + 1))
end = mid;
else
begin = mid + 1;
}
else
{
if(count > 1)
return begin;
else
break;
}
}
return -1;
}
int countrange(vector<int> vec,int begin,int end,int length)
{
int count=0;
for(int i=0;i<length;++i)
{
if(vec[i]>=begin && vec[i]<=end)
++count;
}
return count;
}
};
剑指 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 23 链表中的环(三道题目)
参考:https://blog.youkuaiyun.com/lqy971966/article/details/89818680
思想:双指针
- 判断成环: 取指针 fast 每次移动两个节点,指针 slow 每次移动一个节点,第一次相遇代表此链表成;
- 找环的入口 (区别于链表入口):取两个 slow 指针,一个从 fast 与 slow 第一次相遇点开始,一个从链表入口开始,相遇时即为环入口;
- 求环的长度: 在1的基础上继续走并开始记录路程,当 fast 第二次与 slow 相遇时,fast 比 slow 多走了一整圈,此时 fast 路程减去 slow 路程即为环长度;又因为 fast 是 slow 的两倍速度,因此
pathLen(slow) == pathLen(fast)/2 == len(环)
解释:因为存在环,所以两个指针必定相遇在环中的某个节点上。此时 fast 移动的节点数为 x+2y+z,slow 为 x+y,由于 fast 速度比 slow 快一倍,因此 x+2y+z=2(x+y),得到 x=z。
在相遇点,slow 要到环的入口点还需要移动 z 个节点,如果让 fast 重新从头开始移动,并且速度变为每次移动一个节点,那么它到环入口点还需要移动 x 个节点。在上面已经推导出 x=z,因此 fast 和 slow 将在环入口点相遇。
剑指 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 03 | 数组中重复的数字 | 1037 | 67.5% | 简单 |
剑指 Offer 04 | 二维数组中的查找 | 728 | 40.9% | 简单 |
剑指 Offer 05 | 替换空格 | 725 | 76.6% | 简单 |
剑指 Offer 06 | 从尾到头打印链表 | 705 | 76.1% | 简单 |
剑指 Offer 07 | 重建二叉树 | 529 | 68.8% | 中等 |
剑指 Offer 09 | 用两个栈实现队列 | 634 | 73.9% | 简单 |
剑指 Offer 10- I | 斐波那契数列 | 606 | 33.3% | 简单 |
剑指 Offer 10- II | 青蛙跳台阶问题 | 468 | 42.0% | 简单 |
剑指 Offer 11 | 旋转数组的最小数字 | 678 | 49.9% | 简单 |
剑指 Offer 12 | 矩阵中的路径 | 345 | 44.5% | 中等 |
剑指 Offer 13 | 机器人的运动范围 | 824 | 49.6% | 中等 |
剑指 Offer 14- I | 剪绳子 | 472 | 54.8% | 中等 |
剑指 Offer 14- II | 剪绳子 II | 152 | 30.0% | 中等 |
剑指 Offer 15 | 二进制中1的个数 | 410 | 73.6% | 简单 |
剑指 Offer 16 | 数值的整数次方 | 250 | 32.8% | 中等 |
剑指 Offer 17 | 打印从1到最大的n位数 | 445 | 78.8% | 简单 |
剑指 Offer 18 | 删除链表的节点 | 516 | 59.0% | 简单 |
剑指 Offer 19 | 正则表达式匹配 | 147 | 35.2% | 困难 |
剑指 Offer 20 | 表示数值的字符串 | 195 | 20.6% | 中等 |
剑指 Offer 21 | 调整数组顺序使奇数位于偶数前面 | 546 | 64.3% | 简单 |
剑指 Offer 22 | 链表中倒数第k个节点 | 757 | 78.9% | 简单 |
剑指 Offer 23 | 寻找链表中的环(三道题) | 无资料 | 无资料 | 无资料 |
剑指 Offer 24 | 反转链表 | 581 | 75.1% | 简单 |
剑指 Offer 25 | 合并两个排序的链表 | 363 | 74.1% | 简单 |
剑指 Offer 26 | 树的子结构 | 369 | 46.4% | 中等 |
剑指 Offer 27 | 二叉树的镜像 | 483 | 78.8% | 简单 |
剑指 Offer 28 | 对称的二叉树 | 339 | 57.8% | 简单 |
剑指 Offer 29 | 顺时针打印矩阵 | 668 | 45.2% | 简单 |
剑指 Offer 30 | 包含min函数的栈 | 265 | 57.5% | 简单 |
剑指 Offer 31 | 栈的压入、弹出序列 | 284 | 58.9% | 中等 |
剑指 Offer 32 - I | 从上到下打印二叉树 | 312 | 64.9% | 中等 |
剑指 Offer 32 - II | 从上到下打印二叉树 II | 354 | 68.9% | 简单 |
剑指 Offer 32 - III | 从上到下打印二叉树 III | 352 | 58.7% | 中等 |
剑指 Offer 33 | 二叉搜索树的后序遍历序列 | 319 | 52.1% | 中等 |
剑指 Offer 34 | 二叉树中和为某一值的路径 | 292 | 57.1% | 中等 |
剑指 Offer 35 | 复杂链表的复制 | 257 | 71.2% | 中等 |
剑指 Offer 36 | 二叉搜索树与双向链表 | 275 | 63.9% | 中等 |
剑指 Offer 37 | 序列化二叉树 | 136 | 52.2% | 困难 |
剑指 Offer 38 | 字符串的排列 | 303 | 54.2% | 中等 |
剑指 Offer 39 | 数组中出现次数超过一半的数字 | 342 | 67.7% | 简单 |
剑指 Offer 40 | 最小的k个数 | 935 | 57.6% | 简单 |
剑指 Offer 41 | 数据流中的中位数 | 142 | 55.5% | 困难 |
剑指 Offer 42 | 连续子数组的最大和 | 459 | 59.8% | 简单 |
剑指 Offer 43 | 1~n整数中1出现的次数 | 208 | 45.5% | 中等 |
剑指 Offer 44 | 数字序列中某一位的数字 | 166 | 38.8% | 中等 |
剑指 Offer 45 | 把数组排成最小的数 | 274 | 55.9% | 中等 |
剑指 Offer 46 | 把数字翻译成字符串 | 745 | 53.9% | 中等 |
剑指 Offer 47 | 礼物的最大价值 | 335 | 68.2% | 中等 |
剑指 Offer 48 | 最长不含重复字符的子字符串 | 303 | 45.7% | 中等 |
剑指 Offer 49 | 丑数 | 173 | 64.3% | 中等 |
剑指 Offer 50 | 第一个只出现一次的字符 | 367 | 60.3% | 简单 |
剑指 Offer 51 | 数组中的逆序对 | 378 | 45.8% | 困难 |
剑指 Offer 52 | 两个链表的第一个公共节点 | 279 | 63.1% | 简单 |
剑指 Offer 53 - I | 在排序数组中查找数字 I | 420 | 53.0% | 简单 |
剑指 Offer 53 - II | 0~n-1中缺失的数字 | 512 | 44.2% | 简单 |
剑指 Offer 54 | 二叉搜索树的第k大节点 | 378 | 74.0% | 简单 |
剑指 Offer 55 - I | 二叉树的深度 | 445 | 78.8% | 简单 |
剑指 Offer 55 - II | 平衡二叉树 | 325 | 58.1% | 简单 |
剑指 Offer 56 - I | 数组中数字出现的次数 | 491 | 71.7% | 中等 |
剑指 Offer 56 - II | 数组中数字出现的次数 II | 238 | 79.2% | 中等 |
剑指 Offer 57 | 和为s的两个数字 | 266 | 65.8% | 简单 |
剑指 Offer 57 - II | 和为s的连续正数序列 | 1201 | 69.0% | 简单 |
剑指 Offer 58 - I | 翻转单词顺序 | 323 | 42.5% | 简单 |
剑指 Offer 58 - II | 左旋转字符串 | 672 | 85.3% | 简单 |
剑指 Offer 59 - I | 滑动窗口的最大值 | 415 | 44.3% | 简单 |
剑指 Offer 59 - II | 队列的最大值 | 714 | 47.9% | 中等 |
剑指 Offer 60 | n个骰子的点数 | 206 | 53.7% | 简单 |
剑指 Offer 61 | 扑克牌中的顺子 | 328 | 44.5% | 简单 |
剑指 Offer 62 | 圆圈中最后剩下的数字 | 443 | 62.2% | 简单 |
剑指 Offer 63 | 股票的最大利润 | 298 | 63.9% | 中等 |
剑指 Offer 64 | 求1+2+…+n | 738 | 85.4% | 中等 |
剑指 Offer 65 | 不用加减乘除做加法 | 161 | 55.9% | 简单 |
剑指 Offer 66 | 构建乘积数组 | 179 | 58.3% | 简单 |
剑指 Offer 67 | 把字符串转换成整数 | 225 | 27.6% | 中等 |