本文为《剑指offer》刷题笔记的总结,花费不到两个月的时间将力扣上《剑指offer》的75道题刷了一遍,遇到不会的知识点或者应该做一些记录的题目都将其写在了往日的博客里。
整体来看,这75道题,涉及到常用的数据结构:数组、字符串、链表、栈、队列、树、图,还有一些常用的数据操作和算法:二分法、哈希表、递归、排序、查找、位运算、动态规划、回溯、滑动窗口、双指针、深度优先搜素(DFS)、贪心。
1、数组
(2)剑指offer04.二维数组中的查找。解法:找标志数。正确思路是首先进行非空判断,即排除matrix=[]和matrix=[[]],然后找标志数,找左下角数字作为标志数,它为第一列最大数字,是本行最小数字。如果target 大于该数则向上查找,否则往右查找。具体解法
(4)剑指offer14-I.剪绳子。
(5)剑指offer14-II.剪绳子II。解法:考虑大数越界的情况下的求余问题,可能超过int的范围。大数求余方法包括循环求余(O(N))和快速幂(log2(N))求余。第二者的时间复杂度更低。具体解法
(8)剑指offer39.数组中出现次数超过一半的数字。解法:摩尔投票法或数组排序法。摩尔投票法:记首个元素为n1,众数为x,遍历并统计票数。利用票数和=0可缩小剩余数组区间。当遍历完成时,最后一轮假设的数字为众数。具体解法
(9)剑指offer40.最小的k个数。
(10)剑指offer41.数组流中的中位数(困难)。解法:小顶堆和大顶堆。具体解法
(11)剑指offer45.把数组排成最小的数。解法:快速排序。具体解法
(12)剑指offer49.丑数。解法:动态规划,丑数只包括因子2,3,5,因此“丑数=某较小丑数*某因子”。 具体解法
(13)剑指offer51.数组中的逆序对。解法:归并排序,使用分治,通过不断划分数组,直至到两个部分时再逐一判断。具体解法
(15)剑指offer53-II.0~n-1中缺失的数字。解法:二分法。 具体解法
(16)剑指offer57-I.和为s的两个数字。
(17)剑指offer57-II.和为s的连续正数序列。解法:滑动窗口。具体解法
(18)剑指offer59-I.滑动窗口的最大值。
(19)剑指offer61.扑克牌的顺子。解法:排序。先对数组执行排序,然后判别重复,最后获得最大/最小的牌。具体解法
(20)剑指offer64.求1+2+...+n。解法:递归+逻辑运算符短路效应。具体解法
(21)剑指offer66.构建乘积数组。解法:上、下三角。根据表格主对角线(全为1),可将表格分为上三角和下三角两部分。分别迭代计算下三角和上三角两部分的乘积。引入辅助变量res=1,首先算B[i]的下三角各元素的乘积,直接乘入B[i],然后计算B[i]的上三角各元素的乘积,记为res,并乘入B[i]。具体解法
2、字符串
(1)剑指offer05.替换空格。
(2)剑指offer20.表示数值的字符串。解法:枚举。在遍历字符串的过程种,记录下4种关键信息(是否包含数字、包含小数点,记录小数点的坐标、包含正负号、包含e,记录e的坐标)。具体解法
(3)剑指offer38.字符串的排列。解法:DFS+剪枝。具体解法
(4)剑指offer48.最长不含重复字符的子字符串。解法:滑动窗口+哈希表。本题采用滑动窗口,利用哈希表来做优化。使用哈希表记录每个字符的下一个索引,然后尽量向右移动尾指针来拓展窗口,并更新窗口的最大长度。如果尾指针指向的元素重复,则头指针直接移动到窗口中重复元素的右侧。具体解法
(5)剑指offer50.第一个只出现一次的字符。解法:哈希表。首先遍历字符串s,使用哈希表统计“各字符数量是否>1”,然后再遍历字符串s,在哈希表中找到首个“数量为1的字符”。具体解法
(6)剑指offer58-I.反转单词顺序。解法:双指针。具体解法
(8)剑指offer67.把字符串转换成整数。解法:大数越界。考虑四种字符首部字符、符号位、非数字字符和数字字符。在数字越界处理方面,在每轮数字拼接前,判断res在拼接后是否超过2147483647,若超过则加上符号位直接返回。具体解法
3、链表
(3)剑指offer22.链表中倒数第k个节点。解法:双指针法。具体解法
(4)剑指offer24.反转链表。
(6)剑指offer35.复杂链表的复制。解法:拼接+拆分。考虑构建原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> …… 的拼接链表,如此便可在访问原节点的 random 指向节点的同时找到新对应新节点的 random 指向节点。具体解法
4、栈与队列
(3)剑指offer31.栈的压入、弹出序列。解法:栈的压入与弹出。具体解法
5、树
(1)剑指offer07.重建二叉树。解法:在前序遍历结果中,最左边的元素preorder[0]就是二叉树的根节点,而在中序遍历的结果中,找到preorder[0]元素对应的下标,那么preorder[0]左边所有的元素是属于preorder[0]为根的左子树,preorder[0]右边的元素是以preorder[0]为根的右子树,然后进行递归。具体解法
(2)剑指offer26.树的子结构。解法:先序遍历。具体解法
(3)剑指offer27.二叉树的镜像。
(4)剑指offer28.对称的二叉树。解法:后序遍历。过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。具体解法
(7)剑指offer32-III.从上到下打印二叉树。解法:双端队列。具体解法
(8)剑指offer33.二叉搜索树的后续遍历序列。解法:划分左右子树递归。具体解法
(9)剑指offer34.二叉树中和为某一值的路径。解法:回溯法,包含先序遍历+路径记录两部分。具体解法
(10)剑指offer36.二叉搜索树与双向链表。解法:中序遍历。具体解法
(11)剑指offer37.序列化二叉树。解法:DFS深度优先搜素。具体解法
(13)剑指offer55-I.二叉树的深度。
(14)剑指offer55-II.平衡二叉树。解法:后序遍历。具体解法
(16)剑指offer68-II.二叉树的最近公共祖先。解法:后序遍历--回溯。具体解法
6、位运算
(1)剑指offer15.二进制中1的个数。解法:十进制转二进制。首先将十进制数字转化为二进制数,然后在二进制数中查找字符'1'。具体解法
(2)剑指offer16.数值的整数次方。解法:快速幂。具体解法
(3)剑指offer56-I.数组中数字出现的次数。解法:位运算中的异或。具体解法
(5)剑指offer65.不用加减乘除做加法。解法:位运算中的无进位和与异或,进位和与运算规律相同。具体解法
7、动态规划
(2)剑指offer10-II.青蛙跳台阶问题。解法:动态规划。跳上n 级台阶有 f(n)种跳法。在所有跳法中,青蛙的最后一步只有两种情况:跳上1级或2级台阶,即 f(n)=f(n-1)+f(n-2)。 具体解法
(3)剑指offer19.正则表达式匹配。解法:动态规划。具体解法
(4)剑指offer42.连续子数组的最大和。解法:动态规划。具体解法
(5)剑指offer46.把数字翻译成字符串。解法:动态规划。具体解法
(6)剑指offer47.礼物的最大值。
(7)剑指offer60.n个骰子的点数。解法:动态规划。具体解法
(8)剑指offer62.圆圈中最后剩下的数字。解法:约瑟夫环问题,f(n,m)=[f(n-1,m)+m]%n。具体解法
8、图
(1)剑指offer12.矩阵中的路径。解法:DFS+剪枝。标记当前矩阵元素,搜索下一个单元格,还原当前矩阵元素。具体解法
(2)剑指offer13.机器人的运动范围。解法:DFS。通过分析机器人只能从右或下两个方向进行行走才能到达满足条件的格子(可达解)。具体解法
(3)剑指offer29.顺时针打印矩阵。解法:将矩阵的上t、下b、左l、右r四个边界用于打印的res列表,然后进行从左向右、从上到下、从右到左和从下到上的顺序进行循环(根据边界将元素按顺序添加到res列表的尾部,边界向内收缩1,判断边界是否相遇)。 具体解法
9、贪心算法
剑指offer63.股票中的最大利润。解法:贪心算法,因为股票就买卖一次,那么贪心的想法很自然就是取最左最小值,取最右最大值,那么得到的差值就是最大利润。具体解法
10、找规律
(1)剑指offer43.1~n整数中1出现的次数。解法:通过枚举找规律。具体解法
(2)剑指offer44.数字序列中某一位的数字。解法:找规律。具体解法