23届C++秋招刷题总结
2023-01-05 19:59:32 9 举报
AI智能生成
刷题路线为【代码随想录】
作者其他创作
大纲/内容
前缀树
剑指 Offer II 062. 实现前缀树
需要掌握前缀树的形式:一颗多叉树。字符串之间重合的部分都是一条路径,用一个bool变量表示单词的结束
剑指 Offer II 063. 替换单词
- 创建前缀树,用dictionary初始化这颗前缀树
- 将sentence用空格分割成字符串数组
- 将一个个字符串在前缀树中进行查找,若是有匹配到了词根,就用词根进行替换
- 将sentence用空格分割成字符串数组
- 将一个个字符串在前缀树中进行查找,若是有匹配到了词根,就用词根进行替换
剑指 Offer II 064. 神奇的字典
这道题没啥意思,就是对整个树进行爆搜,对于没有更换过字符的单词,要判断成false
堆
二叉树
二叉树的通用属性
101. 对称二叉树
104.二叉树的最大深度
111.二叉树的最小深度
222.完全二叉树的节点个数
110.平衡二叉树
257. 二叉树的所有路径
404.左叶子之和
513.找树左下角的值
112. 路径总和
543. 二叉树的直径
求二叉树深度的变种题型。对于每一个结点,我们都可以通过求出他左孩子和右孩子的深度,然后相加得到此结点最大的直径长度。由于我们是遍历了二叉树的所有的结点,对所有的结点都进行了如上的判断,因此遍历完整个树之后,肯定是不会漏掉可能更大的答案的
二叉树的修改和构造
226.翻转二叉树
106.从中序与后序遍历序列构造二叉树
654.最大二叉树
617.合并二叉树
二叉树公共祖先
236. 二叉树的最近公共祖先
235.BST的最近公共祖先
BST的属性
700.二叉搜索树中的搜索
98.验证二叉搜索树
530.二叉搜索树的最小绝对差
501.二叉搜索树中的众数
538.把BST转换为累加树
BST的修改和构造
701.二叉搜索树中的插入操作
450.删除二叉搜索树中的节点
669.修剪二叉搜索树
108.将有序数组转换为二叉搜索树
回溯
组合
第77题. 组合
经典组合问题:回溯问题都可以抽象成一颗树:
树的深度由组合的大小决定,树的宽度由原始集合的长度决定
树的深度由组合的大小决定,树的宽度由原始集合的长度决定
216.组合总和III
77题的变种,不仅要在特定数据集合中求出固定长度的组合,还要求组合中的数字和满足题目要求
17.电话号码的字母组合
这个题要建表:把数字对应的字符串提前写好
树的深度由输入字符串的长度决定了,树的遍历方式也固定了,一定是按照拨号顺序来进行组合的
其中变化的就是一个数字对应好几个字符
树的深度由输入字符串的长度决定了,树的遍历方式也固定了,一定是按照拨号顺序来进行组合的
其中变化的就是一个数字对应好几个字符
39. 组合总和
树的深度不定了,但是树的宽度仍旧取决了输入数组的大小
深度不定,所以需要在超过题目条件后就要停止递归
这道题需要把这棵树都遍历完,找到组合和满足要求的
深度不定,所以需要在超过题目条件后就要停止递归
这道题需要把这棵树都遍历完,找到组合和满足要求的
输入数组中,元素不重复,但是同一元素可以使用多次,只需要在递归到下一层时,idx保持不变即可
40. 组合总和 II
难度升级,输入数组中存在重复的元素,但是题目要求,一个元素只能被使用一次
数组中存在重复元素,如何保证结果不重复,这里有两种方法:树枝去重和同层去重。这里使用树层去重
由于组合不强调顺序,所以使用树层去重前,要先对原始数组进行排序,再在每一层,维护一个哈希表,记录使用过的元素
131.分割回文串
树的深度不定,决定于划分字符串的方式,最大深度就是输入字符串的长度
树的宽度也不定,最大也是输入字符串的长度
树的宽度也不定,最大也是输入字符串的长度
在同一层的逻辑是组合出子串,连续的组合,不可以跳过某个字符。
如果这个子串是回文串,则可以递归到下一层去重复这个操作。如果不是,继续组合子串
如果这个子串是回文串,则可以递归到下一层去重复这个操作。如果不是,继续组合子串
93.复原IP地址
算是131分割回文串的变种操作
树的深度定死了,4层,并且在第4层之后,要能用完输入字符串的长度
树的深度定死了,4层,并且在第4层之后,要能用完输入字符串的长度
和131的逻辑是一样的,在同一层组合出子串,然后判断子串的合法性,合法的子串才能递归到下一层
子集
78.子集
通过递归函数,遍历完整个树,不过在遍历的过程中,就要收集得到的遍历结果
90.子集II
包含重复元素的数组,去重,都是用树层去重
树层去重都需要对原始数组进行排序处理,否则得到的结果仍旧有重复得到
491.递增子序列
和子集问题比较类似。
树的宽度,输入数组的长度
树的深度,不定,最大就是输入数组的长度
树的深度,不定,最大就是输入数组的长度
处理逻辑也是先同一层,再递归。
在同一层中,选择逐渐增加的数字添加到集合中,然后递归到下一层。对,一层我们只选一个数
在同一层中,选择逐渐增加的数字添加到集合中,然后递归到下一层。对,一层我们只选一个数
698. 划分为k个相等的子集
这道题有两种视角:站在数字的角度,一颗深度为n,宽度为桶的数量k的多叉树
站在桶的角度,是一颗宽度更宽,但是深度较浅的多叉树
站在桶的角度,是一颗宽度更宽,但是深度较浅的多叉树
站在数字的角度的多叉树,采用常规的回溯就可以写出来。但是时间复杂度一般较高,很难通过
站在桶的角度,可以用DP的状态压缩(我不知道这是什么解题方法),能够大幅度降低时间
站在桶的角度,可以用DP的状态压缩(我不知道这是什么解题方法),能够大幅度降低时间
473. 火柴拼正方形
与698是一样的题,属于698的换皮题
排列
46.全排列
全排列函数,今天用了新的做法:
用树枝去重,去记录同一树枝,之前使用过了哪些数字,避免重复使用
用树枝去重,去记录同一树枝,之前使用过了哪些数字,避免重复使用
树的宽度和深度是数组大小
47.全排列 II
输入数组中有重复元素了。肯定就要想到使用树层去重
树枝去重的目的,是为了避免使用上面树层已经用过的数字
树层去重,是为了避免回溯这棵树,出现两个相同的树枝,
前者是避免树枝有相同的结点,后者是避免整个树有相同的树枝,作用是不一样的
树层去重,是为了避免回溯这棵树,出现两个相同的树枝,
前者是避免树枝有相同的结点,后者是避免整个树有相同的树枝,作用是不一样的
由于排列是讲究顺序的,排列(1,2)与(2,1)是不同的,但是如果是组合就是一样的。
所以对排列使用树层去重是不需要排序原始数组的
所以对排列使用树层去重是不需要排序原始数组的
回溯做排列的题是否有补充?
棋盘问题
N皇后
理论上来说,N皇后问题是一个N叉树,树的深度是N
N皇后问题能转换成N叉树问题后,格外简单
皇后不能同一行,这点在递归遍历中已经自动满足
皇后不能同一列,用一个树枝去重就能解决(或者在斜线检查那做)
皇后不能同一斜线,也就是45°和135°,;两个方向取遍历即可,最后输出结果
皇后不能同一行,这点在递归遍历中已经自动满足
皇后不能同一列,用一个树枝去重就能解决(或者在斜线检查那做)
皇后不能同一斜线,也就是45°和135°,;两个方向取遍历即可,最后输出结果
37. 解数独
贪心
简单题目
445.分发饼干
入门题。可以由常识得到最优解。要么小饼干的大小顺序发,要么先满足要吃大饼干的
1005.K次取反后最大化的数组和
没感觉到最优。数组技巧,取反的次数只有三种可能:将部分负数取反得正、将全部负数取反得正、要对正数进行取反。重点是要排序,对负数取反要优先取反绝对值最大的;对正数取反要优先取绝对值最小的。这样会有最大收益
860.柠檬水找零
挺简单的。没感觉到贪心,算是读题之后领悟到解题技巧。找零时优先使用大面额的零钱,把小面额的5元留在包里。算是一种生活常识吧。之前看别人面试实习还做不出这题呢
中等题目
序列问题
376.摆动序列
摆动序列画出来就是有波峰和波谷的折线,两个相邻的元素差值有正有负。用两个变量记录前后两次差值,通过比较便能得知是否为波峰或者波谷,还是连续的递增或者递减
738.单调递增的数字
这道题的技巧性在于去构造这个数字,也是通过比较前后两个数字的差值,如果低位的数字小于相邻高位的数字,那么高位数字减一,高位之后的低位全部变为9,只要想到这个技巧,这个题就很简单了。
两个维度权衡问题
135.分发糖果
分发糖果是很经典的两个维度去权衡问题。先从左往右遍历,i比i-1的值更大,分的糖果要比前一个多一个;再从后往前遍历,如果i比i+1更大,i的糖果必须要大于i+1的糖果
406.根据身高重建队列
这个题短时间反应不过来是两个维度权衡问题。而且这两个维度如何得到结果其实逻辑有点绕。这题的两个维度分别是身高和位置,要先根据身高从高到低进行排序,然后再按照位置进行插入。按照我的理解,如果插入的位置,已经被其他元素占了,那么先来的元素往后移,为什么?因为先占上的元素肯定是身高更高的,往后移不改变结果的正确性
这道题还有一点让人迷惑的就是,输入数组其实是有很严格的依赖关系的,这种依赖关系会让代码不发生bug。因为这种依赖关系会让数据经过身高重新排序后,再按照位置进行插入排序时,元素的位置一定是挨着的,不会是隔着的
这道题最好用链表完成插入
数组问题
11. 盛最多水的容器
使用两个指针,指向数组的前面和后面,计算次数接水的量,并和ans进行比较,取较大的。
移动指针每次都移动高度较低的,这样我们能保证把潜在的更大的接水量给计算到。
移动指针每次都移动高度较低的,这样我们能保证把潜在的更大的接水量给计算到。
局部最优的思想在于每一次移动指针时,要保留更大的高度,很棒,自己做出来的题
困难题目
区间问题
55.跳跃游戏
跳跃游戏看的是覆盖辐射的范围,如果在某一个点能够辐射到区间终点,那就是能跳到
45.跳跃游戏II
难度升级,要求跳跃次数最少。解题思路也是类似的。要在一次跳跃能够覆盖的范围内,找到下一次跳跃能够跳的最远位置。说白了也就是每一次要,要最大化跳跃距离,局部最优推导到全局最优。
452.用最少的箭引爆气球
排序+统计重合区间。每找到两个重合的区间,更新区间为两个的交集
435.无重叠区间
和452一样的解题,452其实是找,有多少个不重叠的区间,然后435是求多少个重叠区间,两者一个意思
56.合并区间
这道题其实更简单了,和上面的题一个解题方法
763.划分字母区间
解题思路为:统计每一个字符最后的出现位置,在遍历字符串时,收集被遍历字符的最后出现位置,如果此时走到了被收集字符中,最大的一个位置,那么就代表把字符都收集到了,保存结果,进行后面的遍历
134.加油站
加油站是属于贪心中,找不出反例那就是正解的一道题。要能跑完,加的油总量要大于等于消耗的油,这个证明有效吗?无法证明,但是你也找不到反例
解题思路是,从当前i出发,计算剩余油量,如果到j站,剩余油量小于0,那么说明i肯定不是起点,起点另设为j+1,j站不行,正是因为J的消耗田太多才导致没油了。还有一个变量统计总的剩余油量,总的剩余大于0,寻找的i才有意义
53.最大子序和
这道题用DP或者贪心都能做,抓住解题核心:累加和如果小于0了,那么代表这段累加和肯定不满足要求了,从下一个位置开始,重新计算累加和
968.监控二叉树
1.后序遍历
2.设置状态标记,区别三种状态,得到不同的返回值
2.设置状态标记,区别三种状态,得到不同的返回值
动态规划
dp数组推导问题——基础版
509. 斐波那契数
简单题,没啥说的
70.爬楼梯
状态转移公式。dp[0]没有意义。这个题可以拓展成完全背包问题
746. 使用最小花费爬楼梯
楼梯要爬完,楼梯下标从0开始,一直到i-1结束
要爬过最后一个楼梯,也就要爬到第i个位置,所以dp数组初始化长度为size+1
状态转移公式:dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])
要爬过最后一个楼梯,也就要爬到第i个位置,所以dp数组初始化长度为size+1
状态转移公式:dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])
343. 整数拆分
这道题我记得第一次做,想不出来怎么做。这个算法是N^2的
这个题,每一个数,必须要两个数,取乘积最大,利用dp可以获取i之前的数,如果拆分了的话,能够获得的最大乘积
也即是说,一个数n,要拆分后乘积更大,还是不拆分大,通过dp数组的记录,都可以获得
因为一个数被拆分后,被拆分的数还可以继续拆分。这时就要判断,是拆分好,还是不拆分好,max比较嘛
这个题,每一个数,必须要两个数,取乘积最大,利用dp可以获取i之前的数,如果拆分了的话,能够获得的最大乘积
也即是说,一个数n,要拆分后乘积更大,还是不拆分大,通过dp数组的记录,都可以获得
因为一个数被拆分后,被拆分的数还可以继续拆分。这时就要判断,是拆分好,还是不拆分好,max比较嘛
96.不同的二叉搜索树
这道题容易被二叉搜索树给迷惑住了。心里总想着有什么捷径去构造出结点更多的BST
实际上,还是依赖于dp数组对之前的结点数量的BST种类的保存,
结点数量为n,一定是有左子树和右子树之分的,变化的地方在左右子树结点的变化
dp[i] += dp[j-1] + dp[i-j]
空节点也算是一个BST
实际上,还是依赖于dp数组对之前的结点数量的BST种类的保存,
结点数量为n,一定是有左子树和右子树之分的,变化的地方在左右子树结点的变化
dp[i] += dp[j-1] + dp[i-j]
空节点也算是一个BST
二维矩阵问题
62.不同路径
二维矩阵经典题了,上一步只有两个方向,对dp数组进行正确的初始化后,取上一步的两个方向和即可
63.不同路径II
新增了障碍物,凡是有障碍物的地方,都是0,走不通
其余和62没啥区别
其余和62没啥区别
221. 最大正方形
求二维矩阵中,正方形的最大面积。
这个问题,也是两种选择,当前遍历位置,元素==‘1’或者不为1
等于1的话,那么加上这个元素,也许能够形成更大的正方形。但是,要形成更大的正方形,旁边的元素都要是1才行,所以这里要去比较三个元素,取最小值。dp[i-1][j-1] dp[i-1][j] dp[i][j-1]三个取最小值然后再加1。
如果不为1,直接置为0
然后对于整个矩阵的每一次遍历,都要用一个变量记录得到的最大值
这个问题,也是两种选择,当前遍历位置,元素==‘1’或者不为1
等于1的话,那么加上这个元素,也许能够形成更大的正方形。但是,要形成更大的正方形,旁边的元素都要是1才行,所以这里要去比较三个元素,取最小值。dp[i-1][j-1] dp[i-1][j] dp[i][j-1]三个取最小值然后再加1。
如果不为1,直接置为0
然后对于整个矩阵的每一次遍历,都要用一个变量记录得到的最大值
背包问题
01背包
416. 分割等和子集
第一次做,总是做不出来。为什么?因为我忽略了01背包中一个隐含的条件:背包中不会放置超过背包容量的物品,这是由遍历方式得到的!
for(int j = bagWeight; j >= weight[i]; --j) 这里的 j>= weight[i] 就以表明,背包中不会放置超过容量的物品。所以这个题,只需要让物品最大化的放在背包中,如果能放满背包就算找到了解
1049. 最后一块石头的重量 II
这个题,第一次碰到的话,打死都想不到用DP的01背包来做
从01背包的角度来讲,解题思路是将物品装满半容量的背包,如果能装满,则表示石头能被平分为重量相等的两部分,否则就看两部分的差值
算是在416的基础上,换了一层皮
从01背包的角度来讲,解题思路是将物品装满半容量的背包,如果能装满,则表示石头能被平分为重量相等的两部分,否则就看两部分的差值
算是在416的基础上,换了一层皮
494. 目标和
这道题一定要先做转换,不通过公式,降低解题难度,很难做的
从01背包的角度来说,原题意会让背包中装入一个元素后,重量变轻(负值),这就让背包的推导方式变复杂了,目前都是针对正数的背包,所以要将原题进行变换,得到只装正数的背包
从01背包的角度来说,原题意会让背包中装入一个元素后,重量变轻(负值),这就让背包的推导方式变复杂了,目前都是针对正数的背包,所以要将原题进行变换,得到只装正数的背包
474 一和零
物品是字符串,背包是0和1的个数。这个题有两个维度,类似于分发糖果一样,要从两个方面进行考虑,是一个二维平面背包,除此之外,没有其他区别。
完全背包
518 零钱兑换 II
组合问题,先物品再背包。注意初始化
377. 组合总和 Ⅳ
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
先遍历背包,再遍历物品,就可以让背包中的物品,呈现排列。
举个例子,物品1=1,物品2=5,背包等于1时装入了物品1,背包等于5时装入了物品2。当背包等于6时,背包装入了(2,1)以及(1,2)
举个例子,物品1=1,物品2=5,背包等于1时装入了物品1,背包等于5时装入了物品2。当背包等于6时,背包装入了(2,1)以及(1,2)
这个遍历方法适用于01背包吗?
不适用于01背包的滚动数组。因为01背包的滚动数组严格按照物品的顺序,才能正确推导出结果。但是非滚动数组的话,是可以任意交换遍历背包和物品的顺序的,所以这条法则应该也就是适用的
爬楼梯进阶
将爬楼梯每一次爬的步伐改为1~m,问爬到楼顶有多少种方式
这就是同377一样是一道完全背包的排列问题。背包是楼梯层数,物品是每一次爬楼梯的梯数,可以重复使用,然后讲究排列
322. 零钱兑换
这道题的【初始化】和【递推公式】很关键
dp[0] = 0, 其他都是INT32_MAX
dp[j] = min( dp[j], dp[j-coins[i]]+1 ); 是保持原样用币最少还是加一个coins[i]用币最少呢,这里就用min比较一下
同时,由于dp[j-coins[i]]很有可能是4字节最大值,+1就会溢出,因此在这句比较前面还要加一句if判断是否为4字节最大值
dp[0] = 0, 其他都是INT32_MAX
dp[j] = min( dp[j], dp[j-coins[i]]+1 ); 是保持原样用币最少还是加一个coins[i]用币最少呢,这里就用min比较一下
同时,由于dp[j-coins[i]]很有可能是4字节最大值,+1就会溢出,因此在这句比较前面还要加一句if判断是否为4字节最大值
279. 完全平方数
和322完全一样,没啥讲的
139. 单词拆分
乍一看,感觉只能回溯能做,细致的分析一下,其实dp也能做
物品就是单词集合,可以重复使用,完全背包问题
背包是字符串,装满背包==用单词拼凑出字符串
1. 这个题,如何表示物品装入了背包?将单词,顶着背包的容量上限,卡进去
2. 为什么是先遍历背包?先背包是排列,讲究物品之间的顺序,相较于组合,多了很多不同的顺序排列,用组合,单词也许选对了,但是顺序拼错了。本来是可以拼出字符串的,但是算出来拼不出,这不就错误了吗
物品就是单词集合,可以重复使用,完全背包问题
背包是字符串,装满背包==用单词拼凑出字符串
1. 这个题,如何表示物品装入了背包?将单词,顶着背包的容量上限,卡进去
2. 为什么是先遍历背包?先背包是排列,讲究物品之间的顺序,相较于组合,多了很多不同的顺序排列,用组合,单词也许选对了,但是顺序拼错了。本来是可以拼出字符串的,但是算出来拼不出,这不就错误了吗
打家劫舍问题
198. 打家劫舍
常规的状态转移公式,当天的状态是由前面两天推导出来的
dp[i]=max(dp[i-1], dp[i-2]+nums[i])
遍历顺序没有讲究(毕竟是一维数组)
初始化就根据题意初始化好前两个就行
dp[i]=max(dp[i-1], dp[i-2]+nums[i])
遍历顺序没有讲究(毕竟是一维数组)
初始化就根据题意初始化好前两个就行
213. 打家劫舍 II
这个题要转换一下思路,首尾不能挨在一起——抢劫1-n-1或者2-n
两种抢劫方式的最大值就是题解
两种抢劫方式的最大值就是题解
337. 打家劫舍 III
记忆化搜索:通过后序遍历,当前结点有两种选择,偷当前或者偷左右孩子
偷了当前结点,左右孩子就跳过去;不偷当前,就偷左右孩子
偷了当前结点,左右孩子就跳过去;不偷当前,就偷左右孩子
股票问题
121. 买卖股票的最佳时机
只能买入和卖出一次
使用二维dp数组,0表示持有股票,1表示不持有(卖出)股票
初始化很重要,起始持有的话,便是-prices[0]
状态转移通过前一天的持有和不持有进行推导,最后返回值一定是不持有的更大
使用二维dp数组,0表示持有股票,1表示不持有(卖出)股票
初始化很重要,起始持有的话,便是-prices[0]
状态转移通过前一天的持有和不持有进行推导,最后返回值一定是不持有的更大
122. 买卖股票的最佳时机 II
和121只有一个地方有区别:可以无限次数买卖股票。买股票时,荷包里的钱再也不是0了,而是前面买卖股票的最大收益,再去买
714. 买卖股票的最佳时机含手续费
多了一笔手续费罢了,手续费你可以在买入的时候就算上,也可以在卖出的时候才算上。买入+卖出才算做是一笔交易
123. 买卖股票的最佳时机 III
限制了购买次数为2次
188. 买卖股票的最佳时机 IV
购买次数限制到了k次。递推公式和上面的123是一样的,只不过要用for循环罢了
309. 最佳买卖股票时机含冷冻期
将每一天的状态分为买入、卖出和冷静期。
买入的最大收益只能是前一天已经买入或者前一天是冷静期,然后今天买入
卖出的最大收益只能是今天卖出收益以及前一天卖出的最大收益
冷静期的最大收益来自于前一天卖出的收益
买入的最大收益只能是前一天已经买入或者前一天是冷静期,然后今天买入
卖出的最大收益只能是今天卖出收益以及前一天卖出的最大收益
冷静期的最大收益来自于前一天卖出的收益
子序列问题
300. 最长递增子序列
惭愧啊,这道题当时应该是在手机上打出来的,现在就忘记不会做了
- 确定dp数组的形式以及含义
- 一维数组。dp[i] 表示从0-i严格递增子序列的长度
- 递推公式?
for(int j = i-1; j >= 0; --j){
if(nums[i]>nums[j]){ dp[i] = max(dp[i],dp[j]+1); }
}
- 初始化
全部置为1
- 一维数组。dp[i] 表示从0-i严格递增子序列的长度
- 递推公式?
for(int j = i-1; j >= 0; --j){
if(nums[i]>nums[j]){ dp[i] = max(dp[i],dp[j]+1); }
}
- 初始化
全部置为1
674. 最长连续递增序列
这道题是300的简单版。674要求子序列必须是连续的,300没这样的要求。所以300要和i之前的每一个j比较,试图找到最大的递增子序列
718. 最长重复子数组
开始进入二维dp数组了
这道题不要想复杂了,由于题目要求是连续子数组,所以如果i和j的数字不相同,那么之前的状态是不能在使用的!
这道题不要想复杂了,由于题目要求是连续子数组,所以如果i和j的数字不相同,那么之前的状态是不能在使用的!
1143. 最长公共子序列
当当当当,公共子序列来了。公共子序列和公共子数组,二字之差,差别巨大,子序列不讲究元素的连续性,只要相对顺序不发生改变即可。可以利用之前的状态!
1035. 不相交的线
1143最长公共子序列的换皮题,一模一样的解法
392. 判断子序列
有点删除序列那个味道了,删除长的序列中的字符
115.不同的子序列
第一次做不了,第二次还是做不了,哈哈哈
在判断子序列的基础上,还要统计子序列出现的次数,难度陡增
在判断子序列的基础上,还要统计子序列出现的次数,难度陡增
核心点是抓住s[i] 是否等于 t[j]这个点,对于392来说,相等就在上一个匹配的基础+1,不想等就“删除”母序列的长度
然后对于这道题,相等的情况下,可以沿用对角线上一个匹配的值,还可以沿用不使用当前母序列字符匹配的值,如果不相等,只能沿用不使用母序列字符匹配的值
583. 两个字符串的删除操作
我个人感觉,这个题把dp数组这种数学概念的思维玩尽了
首先要确定dp数组的函数,dp[i][j]表示word1[:i] 与 word2[:j] 相同的最小步数.这里要注意,经过删除之后的字符串一定是相等的
递推公式:由三个方向推导而来,删除i,删除j,或者两个都删除,毕竟左邻居、上邻居、左上角邻居都已经是相等的状态了,删除到哪个状态的次数最少选哪个
首先要确定dp数组的函数,dp[i][j]表示word1[:i] 与 word2[:j] 相同的最小步数.这里要注意,经过删除之后的字符串一定是相等的
递推公式:由三个方向推导而来,删除i,删除j,或者两个都删除,毕竟左邻居、上邻居、左上角邻居都已经是相等的状态了,删除到哪个状态的次数最少选哪个
这道题还有一种逆向思维的解题方法:先求出最长公共子序列,然后用两个字符串的长度-最长公共子序列长度*2。1143 YYDS
72. 编辑距离
难度升级,操作方式从删除,增加到了删除、插入以及替换三种方式,这意味着题目变得更加复杂
但是,插入和删除其实一个道理,两者相等,较短的插入一个与较长的删除一个,不是一个意思,吗?
替换就是在dp[i-1][j-1]的基础上,增加一次操作次数,所以这道题只是在583的基础上,增加了替换的功能,而且替换的递推还贼简单
替换就是在dp[i-1][j-1]的基础上,增加一次操作次数,所以这道题只是在583的基础上,增加了替换的功能,而且替换的递推还贼简单
牛客网NC35变种题,插入、删除、替换分别有一个代价(IC、dc、rc),变种题其实考察的是对于插入和删除的掌握是否透彻。
插入操作,就是要在dp[i][j]的基础上,插入一个字符,变成dp[i+1][j]。但是dp[i+1][j]的状态是未知的,所以插入操作等价于str2删除一个元素,也就是从dp[i][j]变成dp[i][j-1],str2删除一个字符的代价,等价于str1插入一个字符的代价,代价就是ic
删除操作,也就是从dp[i][j]变成dp[i-1][j],代价就是dc
替换操作,也就是从dp[i][j]变成dp[i-1[j-1],代价就是rc
插入操作,就是要在dp[i][j]的基础上,插入一个字符,变成dp[i+1][j]。但是dp[i+1][j]的状态是未知的,所以插入操作等价于str2删除一个元素,也就是从dp[i][j]变成dp[i][j-1],str2删除一个字符的代价,等价于str1插入一个字符的代价,代价就是ic
删除操作,也就是从dp[i][j]变成dp[i-1][j],代价就是dc
替换操作,也就是从dp[i][j]变成dp[i-1[j-1],代价就是rc
647. 回文子串
这道题有两种比较好的做法,一是双指针法(从剑指offer学到的),二是dp动态规划
双指针法的思维很巧妙。从起始点出发,向两边拓展开来。遇到不是回文子串了,就退出。对字符串的每一个位置,都要做这样的“测试”,并且,起始点可以是一个字符开始,也可以是两个字符一起开始,也就是a,或者aa。统计最后的结果
双指针法我很熟练的,dp反而不太熟悉。这次的dp也是二维数组,不过和之前有不一样了
二维dp数组出现在【矩阵图】、【背包】、【子序列】这三种问题居多
【矩阵图】的横纵坐标就是图上的坐标,这里没其他的变化
【背包】的横坐标一般表示背包的容量、纵坐标表示物品的选择
【子序列】问题,横纵坐标一般表示不同的字符串
在这道题,dp[i][j]表示用【i-j】组成的字符串是否是回文字符串,这里i肯定是小于等于j的
二维dp数组出现在【矩阵图】、【背包】、【子序列】这三种问题居多
【矩阵图】的横纵坐标就是图上的坐标,这里没其他的变化
【背包】的横坐标一般表示背包的容量、纵坐标表示物品的选择
【子序列】问题,横纵坐标一般表示不同的字符串
在这道题,dp[i][j]表示用【i-j】组成的字符串是否是回文字符串,这里i肯定是小于等于j的
当i和j指向的字符不想等的话,肯定不是回文字符串
如果相等的话,还需要去判断【i+1,j-1】组成的字符串是否为回文字符串
如果相等的话,还需要去判断【i+1,j-1】组成的字符串是否为回文字符串
核心思想和双指针法是类似的
5.最长回文子串
和647基本上一样,通过dp数组来获取回文字符串。
当遇到回文字符串时,判断这个串的长度是不是更长,更长就记录下这个串的起始和终点坐标
当遇到回文字符串时,判断这个串的长度是不是更长,更长就记录下这个串的起始和终点坐标
516. 最长回文子序列
回文子序列的题比回文字串要简单一些,应该说是判断情况要简单一点
回文字串要字符匹配相等的时候,需要分两种情况进行讨论:【j-i小于等于1】、【去掉i和j的字符串要是回文】
回文子串字符匹配不上时,就直接是FALSE,不需要理会
回文字串要字符匹配相等的时候,需要分两种情况进行讨论:【j-i小于等于1】、【去掉i和j的字符串要是回文】
回文子串字符匹配不上时,就直接是FALSE,不需要理会
但是回文子序列不一样
回文子序列在字符匹配上的时候,直接在去掉i和j的结果上+2
如果字符匹配不上,可以删除一个字符,删除有两种选择,删除i或者删除j,选择最大的那一种
回文子序列在字符匹配上的时候,直接在去掉i和j的结果上+2
如果字符匹配不上,可以删除一个字符,删除有两种选择,删除i或者删除j,选择最大的那一种
图论
332.重新安排行程
79. 单词搜索
就是很常规的,在矩阵中进行搜索。矩阵搜索一般就是四个方向,使用vis数组记录遍历过的点
207. 课程表
首先,这个题是针对拓扑排序做的搜索算法
什么是拓扑排序呢?就是图中没有成环的,然后对图的遍历得到的序列就是拓扑排序。
这个题用来一个新技巧:
1. vis的状态从0-1变为0-1-2三种状态,不仅仅表示这个顶点被访问了,还要辨别这个结点是在搜索中,还是搜索过了。
因为对于这个题来说,没有相邻结点的时候,就表明这个结点已经遍历干净了,就要置为2这个状态
什么是拓扑排序呢?就是图中没有成环的,然后对图的遍历得到的序列就是拓扑排序。
这个题用来一个新技巧:
1. vis的状态从0-1变为0-1-2三种状态,不仅仅表示这个顶点被访问了,还要辨别这个结点是在搜索中,还是搜索过了。
因为对于这个题来说,没有相邻结点的时候,就表明这个结点已经遍历干净了,就要置为2这个状态
210. 课程表 II
同207,方法是一样的,只是需要用数据结构将上课的顺序给保存下来。
这里针对示例的返回状态,我们可以发现,用栈这种LIFO特性刚刚满足要求
210才是将vis的三种状态应用得很彻底的题,因为只有当vis状态为2时,才能用stack将结点装进去
这里针对示例的返回状态,我们可以发现,用栈这种LIFO特性刚刚满足要求
210才是将vis的三种状态应用得很彻底的题,因为只有当vis状态为2时,才能用stack将结点装进去
数学
478. 在圆内随机生成点
拒绝采样法:在与圆内切的正方形中,生成两个随机数,如果生成的随机数在圆外,重新生成(我之前也是这么想的。靠!)
记住生成随机数的两个类:
default_random_engine gen;
uniform_real_distribution<double> dis;
double r = dis(gen);
default_random_engine gen;
uniform_real_distribution<double> dis;
double r = dis(gen);
136. 只出现一次的数字
位运算。两个重复的数字,通过异或运算,找到没有重复的那个数字
异或运算有以下三个性质。
任何数和 00 做异或运算,结果仍然是原来的数,即 a \oplus 0=aa⊕0=a。
任何数和其自身做异或运算,结果是 00,即 a \oplus a=0a⊕a=0。
异或运算满足交换律和结合律,即 a \oplus b \oplus a=b \oplus a \oplus a=b \oplus (a \oplus a)=b \oplus0=ba⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。
任何数和 00 做异或运算,结果仍然是原来的数,即 a \oplus 0=aa⊕0=a。
任何数和其自身做异或运算,结果是 00,即 a \oplus a=0a⊕a=0。
异或运算满足交换律和结合律,即 a \oplus b \oplus a=b \oplus a \oplus a=b \oplus (a \oplus a)=b \oplus0=ba⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。
剑指 Offer II 001. 整数除法
这道题有三个点要注意:
第一是被除数为INT_MIN时,单独判断,由除数是1还是-1直接得到结果,不用运算;
第二是要将被除数和除数都转换为负数。这是因为负数的范围更大,如果将负数转换为正数,会导致结果错误;
第三是使用二分法加速计算的过程(除数翻倍,类似于2次幂的加速计算一般)
第一是被除数为INT_MIN时,单独判断,由除数是1还是-1直接得到结果,不用运算;
第二是要将被除数和除数都转换为负数。这是因为负数的范围更大,如果将负数转换为正数,会导致结果错误;
第三是使用二分法加速计算的过程(除数翻倍,类似于2次幂的加速计算一般)
剑指 Offer II 002. 二进制加法
此题是模拟二进制加法的过程,类似于两条链表数字相加一般。
用一个变量表示进位即可,还是很简单的
用一个变量表示进位即可,还是很简单的
剑指 Offer II 003. 前 n 个数字二进制中 1 的个数
两点需要记住:
第一是求一个整数的二进制表达的1的个数方法a = a & (a-1)
第二是此题可以使用dp加速解题,使得时间复杂度变为O(n)
第一是求一个整数的二进制表达的1的个数方法a = a & (a-1)
第二是此题可以使用dp加速解题,使得时间复杂度变为O(n)
剑指 Offer II 004. 只出现一次的数字
将所有数字的每一个位相加,能被3整除的就不是那个数字的位,不能整除的就是那个数字的位
数组
704. 二分查找
最简单的二分查找。有序,无重复数字,寻找元素
27. 移除元素
姑且认为慢指针所覆盖的元素都是不包含val的,所以,快指针遍历到的等于val的元素,都不得加入到慢指针中。相反就可以
977. 有序数组的平方
双指针+辅助数组。输入数组的格式决定了此题能够使用双指针法:数组要么是整段有序的,要么是分段有序的(段次为2),两个指针就能表示这两段有序的数组
209. 长度最小的子数组
滑动窗口解题
窗口内的内容是什么?
什么时候扩大窗口?
什么时候缩小窗口
链表
剑指 Offer 06. 从尾到头打印链表
链表的遍历和栈的使用,太简单
剑指 Offer 24. 反转链表
经典链表题型。必须时刻都会做。迭代和递归两种做法都要能做。核心思想:取出当前结点,重置结点的指向(脱离当前链表)
剑指 Offer 35. 复杂链表的复制
新题型。将链表和哈希表结合在一起,挺有意思。用哈希表创建处一张原结点和副本结点的映射关系。通过原结点查表得到新节点的前后关系(指针指向)
剑指offer II 25. 链表中的数字相加
用链表表示一个整数(头结点是最低位,头结点是最高位),两个整数相加。难点1:进位;
如果链表头结点表示的整数的最高位,为了从低位相加,有两种办法:
反转链表
使用栈保存链表结点,再依次弹栈
使用栈就可以避免反转链表,是进阶的做法
剑指offer II 26. 重排链表
这道题一考思维,二考对链表删除插入操作的熟悉程度。根据题意要能明白,只要将链表一分为二,让后半部分链表反转后,两个链表合并即可
既然涉及到反转链表,那么就有两种办法
第一:反转链表函数
第二:将链表保存早栈中,弹栈即可得到顺序相反的结点
剑指offer II 27. 回文链表
链表一分为二,然后反转后半部分链表,按个比较。没有太多难点,掌握分割链表和反转链表即可解题
剑指offer II 28. 展平多级双向链表
将链表和DFS结合在一起,思维的体量上有难度。主要是明白如何变换链表,同时紧紧抓住递归函数中当前层和下一层返回结果的关系,这道题通过debug倒也是不难。
剑指offer II 29. 排序的循环链表
这道题难点在于插入情况的梳理,一共有四种插入情况。着重需要注意有重复元素的case,需要debug检查
203.移除链表元素
考察链表结点的删除和头结点的使用。这个题不使用头结点将会变得十分复杂。
这个题除了用迭代法做,还可以用递归来做。有一些类似于回溯,递归到链表尾部,然后在递归函数返回前,判断是返回nullptr还是当前结点,去更新上一层结点的next指针
707.设计链表
链表增删改查全方面考察。这是我力扣上做出来的第一道题
24. 两两交换链表中的节点
这道题是模拟。交换链表中的相邻两个结点,还涉及左边的第三个结点。实际上是三个结点的next指针在作改变。第二个是理清楚向后移动的方式要注意,交换完后最右边的结点向后试探两步,如果不行就结束交换
19.删除链表的倒数第N个节点
技巧:双指针。删除倒数第n个结点,就让两指针间隔n,当right指针到达最后一个结点时,left正是要删除的结点的前一个结点。技巧2:头结点。凡是需要删除结点的题,都优先考虑使用头结点。
面试题 02.07. 链表相交
解题方法1:重复走。指针1遍历完链表1后,从头开始遍历链表2,指针2相反。如果两链表相交,必定会在某个结点相遇(走过的结点数量是相同的),如果没有相遇,则代表不相交。
142.环形链表II
经典的数学推导。快指针走过的结点数量是慢指针的2倍,两者相遇的位置+环的长度*n,就是链表头到环入口的长度
哈希表
剑指 Offer 50. 第一个只出现一次的字符
剑指 Offer II 033. 变位词组
无技巧硬哈希:将单词转换成字符出现次数的新字符
技巧:将单词排序,异位词排序后相等
剑指 Offer II 034. 外星语言是否排序
直接哈希,没啥说的
剑指 Offer II 035. 最小时间差
这道题是技巧+哈希。将字符串转换为分钟数,为了比较当天的23:59和第二天的00:00,需要对小于12点的时间增加一天的分钟数1440,从而成为第二天的时间
时间效率对比
分钟数存于数组,sort排序,找最小差值:nlogn
分钟数存于multiset,遍历找最下差值:logn
分钟数存于2160长的数组,遍历找最小差值:n
空间换时间
242.有效的字母异位词
哈希表统计字符出现的次数,然后进行比较
383. 赎金信
和242类似
349. 两个数组的交集
哈希表统计数字出现的次数,然后进行比较。思路和上面是一样的,处理起来一些许差异
第202题. 快乐数
要转个弯。无限循环的数字用哈希表保存,出现重复了就能判断为无限循环数字
1. 两数之和
哈希表空间换时间。用哈希表的O(1)查询效率去掉一层循环
第454题.四数相加II
要转一下脑筋。是两数之和的变种题。将a+b+c+d=0转换成a+b=-(c+d)。用空间换时间,将4层循环降到2层循环
128. 最长连续序列
这道题要求是O(n)的时间复杂度。为了做到这一点,这道题有两个技巧:
第一是使用哈希表进行查询,将查询的时间复杂度降到O(1)
第二是在使用哈希表时,为了避免重复的查询过程,一定是从连续子序列的起点开始查
如果不是起点,那么他的左边或者右边(看你的查询方向)一定是在哈希表中的,跳过,
这样操作的目的是降低时间复杂度,避免时间复杂度恶化到O(n^2)
第一是使用哈希表进行查询,将查询的时间复杂度降到O(1)
第二是在使用哈希表时,为了避免重复的查询过程,一定是从连续子序列的起点开始查
如果不是起点,那么他的左边或者右边(看你的查询方向)一定是在哈希表中的,跳过,
这样操作的目的是降低时间复杂度,避免时间复杂度恶化到O(n^2)
字符串
剑指 Offer II 015. 字符串中的所有变位词
哈希表统计次数+滑动窗口
剑指 Offer II 016. 不含重复字符的最长子字符串
同上
剑指 Offer II 017. 含有所有字符的最短字符串
n2的做法就是每移动一次窗口,就要去检查字符是否全部包含,时间复杂度是n2.
剑指 Offer II 019. 最多删除一个字符得到回文
回文检查+模拟。最多删除一个,当出现不匹配时,可以删除左边,也可以删除右边
剑指 Offer II 020. 回文子字符串的个数
双指针法,从中间往外延展,变大子串的长度,判断是否为回文串。从中间延展,有奇偶之分,从当前位置延展,或者和旁边一起延展
344.反转字符串
原地翻转字符串,很简单的交换
题目:剑指Offer 05.替换空格
简单的做法是使用辅助的字符串,进阶的做法是将原先的字符串延展要求的长度,然后从后往前填充字符串
151.翻转字符串里的单词
这道题是有技巧的:两次翻转字符串就能让整个字符串呈现出字符顺序翻转的效果。如果你自己去推导一下坐标的变换,就能理解其中的缘由
题目:剑指Offer58-II.左旋转字符串
上面的变种题,先将字符串整体翻转,然后再翻转子字符串,就能实现字符串的左旋效果
28. 实现 strStr()
KMP算法
459.重复的子字符串
KMP算法
双指针法
滑动窗口
209. 长度最小的子数组
滑动窗口解题
窗口内的内容是什么?
什么时候扩大窗口?
什么时候缩小窗口?
2024. 考试的最大困扰度
每日一题:本质是翻转字符串,用规定的次数,让翻转后的字符串有最长的连续相同字符。固定翻转的方向,用滑动窗口去找:当翻转次数不超过允许值时,最长的长度
1004. 最大连续1的个数 III
这个题同2024一样。都是翻转,只需将0翻转为1,在k次翻转内统计连续1的最大长度
674. 最长连续递增序列
这道题也可以用dp来做
这算是一个滑动窗口题。姑且设定滑动窗口内的元素都是单调递增的,那么窗口最后一个元素就是最大的,如果之后遍历的元素,小于或者等于右窗口值,那么窗口就要重置为1了,慢指针直接移动到右窗口的位置
1658. 将 x 减到 0 的最小操作数
这道题解法很简单,但是要想到这种解法,需要脑筋转一个弯。这题实际上提炼出来就是找到最长的连续子序列,其序列累加和等于target这么一个问题,而这个target==整个数组累加和 - x
1456. 定长子串中元音的最大数目
- 643. 子数组最大平均数 I
- 1052. 爱生气的书店老板
1423. 可获得的最大点数
26. 删除有序数组中的重复项
慢指针指向的是合法元素数组的最后一个元素,快指针是遍历原数组的。由于不能允许重复,且数组是有序的,可以认为,慢指针之前的元素,在快指针之后都不会再遇到了。所以只需将慢指针指向的元素和快指针指向的元素相比较即可
80. 删除有序数组中的重复项 II
难度升级。允许重复一次。由于数组是有序的,重复的数字是挨在一起的,所以,快指针要和慢指针的前一位作比较。如果这道题改为重复k次,那么快指针就要和慢指针之前的k-1位比较
27. 移除元素
姑且认为慢指针所覆盖的元素都是不包含val的,所以,快指针遍历到的等于val的元素,都不得加入到慢指针中。相反就可以
283. 移动零
移动0有两种做法
第一种是移动元素的变种。移动元素是用后面合法的元素覆盖掉不合法的元素。在移动元素之后,后面一截补上0即可
第二种方法效率更高。左指针表示不含0元素的序列的end,右指针表示需要处理的序列的begin。右指针凡是遇到一个非0的元素,就将该元素交换到左指针的末尾,同时左指针后移
75. 颜色分类
这道题虽然有三个元素要操作,但我们可以只排序好0和1或者0和2即可,剩下的就自动排好了
第一种解法:0移动到最前面,2移动到最后面。先操作2,如果遍历到了2,就将2交换到末尾。但此时有一个注意的,如果交换后还是2,还需要继续交换(back指针已经前移),直接交换后不再是2
因为我们是从前往后遍历的,在p~back这段区间是没有被遍历过的,如果交换完,p的元素仍然是2,不能跳过,因为不能保证p之后的元素都是2. 但是p == 0就不一样的,p之前的所有元素都已经放入front里了,如果交换完等于0,那只有一个可能,交换前两指针相等。
977. 有序数组的平方
双指针+辅助数组。输入数组的格式决定了此题能够使用双指针法:数组要么是整段有序的,要么是分段有序的(段次为2),两个指针就能表示这两段有序的数组
第15题. 三数之和
双指针解法。先排序,再用指针寻找元素之和
581. 最短无序连续子数组
双指针+排序。题目要求最短的无序数组的长度,使得经过排序之后整个数组都有序了。
先将数组进行排序,得到有序版本,并同原数组进行比较
时间复杂度O(nlogn)
先将数组进行排序,得到有序版本,并同原数组进行比较
时间复杂度O(nlogn)
栈
232. 用两个栈实现队列
主栈负责添加元素,子栈负责删除元素
主栈中的元素,先进的在栈底,无法操作。但是将主栈的元素弹栈压栈到子栈后,子栈栈顶的元素即为主栈栈底的元素,刚好反过来了。
155. 最小栈
两个栈。主栈正常保存数据,子栈负责保存对应位置的最小元素
这里利用到了栈先进后出的特性:后进的元素如果没有被弹出,那么先进的元素一定就在栈中
20. 有效的括号
将左括号压入栈中,遇到右括号弹栈匹配。栈经典应用场景——括号
150. 逆波兰表达式求值
将数字压入栈中,遇到运算符弹两次栈进行运算
C 语言的字符串转整数的库函数:atoi
剑指II-037. 小行星碰撞
基本上碰撞问题都能用栈进行解决。想清楚哪些情况会发生碰撞,针对碰撞去写条件,不会碰撞的就不管。
单调栈
单调栈本质上也是栈,只是在使用栈时,让栈中的数据满足单调递增或者单调递减的规律,帮助我们解题
739. 每日温度
经典的单调栈题型。从栈底到栈顶保持单调递减的规律(因为题目要求的是多少天之后温度升高),栈中存放的元素是下标(要求时间间隔)。栈中元素,从栈底到栈顶,每一个都在等待大于他自身温度的那一天到来。
496. 下一个更大元素 I
每日温度的变种题型。首先挨个计算出nums2数组中,当前元素的下一个更大元素是谁,用哈希表保存,方便查询。再遍历一遍nums1,依次查询哈希表,得到最后结果
503. 下一个更大元素 II
在496的基础上,增加了一个条件,循环数组。一般来说处理循环数组的方法就是将其延长一倍,但是道题由于有重复元素,这样处理起来还挺麻烦。更简单的做法是遍历两次这个数组
42. 接雨水
接雨水可以用单调栈做。栈中的元素也是按照从栈底到栈顶单调递减的方式保存,遇到大于栈顶的元素时,弹栈一次,获取两个栈顶元素,加上当前元素,组成一个两高一低的凹形,然后计算凹进去能接的雨水的面积
解题的核心或者技巧就在【弹栈一次,但是要获取栈中两个元素】。遇到更大的高度后,弹栈一次,将最低的高度弹出来,然后再获取下一个栈中的元素(大于等于刚才弹栈的元素),两高一低中间组成凹坑,便能接水了。
84. 柱状图中最大的矩形
此题和接雨水很相似,接雨水获取两次栈顶元素,加上当前元素3个值组成凹形,此题是组成凸形。单调栈的顺序和接雨水要相反,然后要在原数组的基础上,前后增加两个0
这道题有一个隐藏满足的条件,中间的最高的柱子,弹栈弹走了之后,其依然会对之后计算产生影响。产生影响的方式便是它的下标位置,
因为我们每次取高度都是取mid对应的,也就是三者之间最高的那个值,但是宽度的取值就不是固定的了,宽度会随着计算的增加,越往后越大。这里一句两句说不清楚。但是和接雨水是很相似的,两者在数据的处理上,都有点奇妙
剑指II-040. 矩阵中的最大矩形
队列
239. 滑动窗口最大值
滑动串口+优先队列。这道题数据量很大,不作优化的话是会超时的。
优化方法:优先队列top为最大值,如果这个最大值还在滑动窗口中,那么无需对优先队列执行删除元素的操作(删除在滑动窗口之前的元素)。
347. 前 K 个高频元素
哈希表+优先队列+大小根堆选择
前k个最大的,要用小根堆,反之则用大根堆
二分查找
二分查找思想很简单,但是细节很恐怖
剑指 Offer 53 - II. 0~n-1中缺失的数字
剑指 Offer 11. 旋转数组的最小数字
34. 在排序数组中查找元素的第一个和最后一个位置
240. 搜索二维矩阵 II
这道题不需要使用DFS或者BFS,直接两个循环遍历即可。常规的做法是对每一行都使用二分查找算法,时间复杂度就是mlogn
进阶的做法是Z字形搜索,代码很简单,但是为什么可以这样搜索,需要数学证明,没来得及看
进阶的做法是Z字形搜索,代码很简单,但是为什么可以这样搜索,需要数学证明,没来得及看
74. 搜索二维矩阵
这个比240简单一些,毕竟数组的排序方式变简单了。这道题的解法就是两次二分查找,第一次二分查找是寻找行内元素大于target的行,第二次则是去每一行总查找target
前缀和
238. 除自身以外数组的乘积
除自身以外,那么就可以分为前缀和后缀,分别计算出前缀乘积数组以及后缀乘积数组,就能在不使用除法的情况下,解出此题
0 条评论
下一页