中级提升班1:
主要是刷题:
贪心策略,把绳子最右侧的点放在一个存在的点上,然后从右往左看,把绳子左侧的端点定位在数轴上,然后在数轴上找到大于等于左侧断点处最左的位置(二分法),然后下标计算得到长度
更好的方法
滑动窗口
确定一个左指针,每次定位在数轴中的每一个点,确定一个右指针,根据做指针再往左推L个位置。由于左右指针都不回退,所以整个时间复杂度为O(N),没有代码
16:37
简单的策略是先尽量使用8类型的袋子
这里一个取巧的方法是,当剩余未搞定苹果的个数大于24个的时候,就不用接着试了。考虑一下大于24这个数字是怎么来的,假设一个大于24的数字M,那么M可以分解为m+24,那么肯定是之前使用了3*8个,剩余m,发现m用6整除不了,然后用2*8个,剩余m+8用6亦然整除不了,直到m+16,m+24,如果想用6解决m+24的话,其实6要先解决24,然后发现m之前已经算过解决不了了。
38:44:当发现一道面试题,入参是一个整数,出参也是一个整数,那么先写出特别傻的代码,然后分析规律,做优化
44:30 举例,关于先后手的递归+循环中的递归
先手和后手两只动物吃草,草的总数是一定的,每次规定只能吃4的n次方那么多草,请返回谁会赢
第20行中,winnner(n-base)是子过程,子过程中后手胜利,代表母过程即先手胜利,while中每次尝试自己吃更多的草能不能赢
1:05,这个递归的过程讲解,然后你打印这个结果,再总结规律,
得到下面的代码
预处理的技巧 1:10
我生成两个辅助数组,其中一个数组统计从左到右有几个G,一个从右到左统计有几个R,做的时候取一个分界线,分界线左边都是准备染色为R,分界线右边都是准备染色为G
1:28
一个矩阵中有几个子矩阵,时间复杂度是o(N^4)的,因为点两个随机的点,两个随机点的概率都是o(N^2)的,再相乘(构成一个矩阵),复杂度就成了o(N^4)了。正方形的概率是o(N^3).
使用两个for循环分别枚举长和宽,代表了任何一个左上角点的随机位置,使用第三个for循环来枚举边长(存在一个竖着先到边界或者一个横着先到边界的问题),再使用一个right矩阵和一个down矩阵,分别记录每一个点右侧有多少连续的1,记录每一个点下面有多少个连续的1
1:56
这种问题需要使用二进制来拼凑,先用1-5的等概率,产生等概率返0-1的,1-2返回0,4-5返回1,3返回重新来
等概率返回1-7,其实就是等概率返回0-6
只要数6有几个二进制位,需要3个,生成7的话就重做
第二问和第一问一样,第三问就连续生成两次,如果生成00或01就重做,得到10就算1,得到01就算0
———————————————————————————————————————————
中级提升班-2
给定一个非负整数n,代表二叉树的节点数,请问共能生成多少种二叉树的结构
假设N个节点的种类是F(N),假设左数有i个节点,左数可能性就是F(i),那么右数的可能性就是F(N-i),总共的可能性九四F(i)*F(N-i),这里的i是从0变化到N-1的,把这些可能性全加起来,就是总的F(N)
code
8:00 括号串
我们应该怎么判断括号完整还是不完整,从左往右遍历一遍遇到左括号就count++,遇到右括号就是count--,第一个标准是,整个遍历的过程中不能出现count小于0的情况,第二个标准是遍历结束之后,count必须等于0
code:15:20
遇到的右括号,但是此时count为0,就说明之前没有多余的左括号可以和这个右括号配对了,所以直接在answer中加一就行了,代表需要使用多少个左括号,如果最后count大于0了,就说明之前有多余的左括号还没有配对,需要在answer中加上,代表还需要添加多好个右括号
17:46 给定一个数组,求差值为k的去重数字对
比如[3,2,7,5,0]这样一个数组,需要找到所有差值为2的,且不能重复,那答案就是(3,5)(5,7)(0,2),做法就是把所有这些数都放到哈希表里,然后找当前数字+差值的数字存不存在,就能避免重复,利用哈希表的查询很节省时间,没有code
23:00 magic操作
29:00 开始讲解, 两集合平均值相等时无法magic,一个magic操作其实只能从平均值大的集合中拿数,拿到平均值小的集合中
40:00 code,累加和记为double类型,因为平均数可能是小数,但是要去的数肯定是整数
较大的集合排个序,这样方便找平均值,较小的集合用哈希表记录下来,搬运的时候需要保证小集合里没有这个数
———————————————————————————————————————————
中级提升班3
5:12 题目四
从左往右遍历遇到左括号就count++,遇到右括号就count--,count产生的最大值就是最大深度
9:07补充题目 有一个有左括号和右括号的字符串,找到最长的有序括号子串
20:35 举例说明如何用dp来求这个问题
code:24:17
26:43 题目五
使用一个辅助空间来存放栈顶元素,维护的另一个栈是从小到大排序的
30:43 题目三
这是一个从左往右的尝试模型,F(I)代表从I位置开始,往后还有多少种可能,主函数在调用的时候直接返回F(0)就行了,
决策行为只有三种,当i位置是0时,没有办法转,可能结果是0,当i位置不是零,那么方法数是F(I+1),如果i位置和i+1位置之和小于26,那么还有一种方法数是F(I+2)
code:42:00
这个第26行代码是一个不好懂的地方,其实第26行和第33行的地址是相等的,他确定了整个大函数的返回时机,如果i位置已经来到了最后一个,后面没有i+1位置了(也就是25行的判断),那就返回res,如果还有后一个位置且小于26(30行的判断),那res需要类加上另一种可能才能返回
44:00 转动态规划表
46:30 题目七
二叉树的每一个节点都有一个int型权值,给定一个二叉树,要求计算出从根节点到叶节点的所有路径中,权值和最大的值是多少
基础版的code,讲解在54:00
59:00 套路解
两个方法都可以
1:01 给定一个非负整数二维数组matrix,每行每列都是有序的,再给定一个非负整数aim,请判断aim是否再matrix中
最快的方式是从矩阵的右上角开始找,然后从右往左滑动,具体还是看视频吧,非常巧妙
变化形式,1:04:48,在一个二维数组中,只有0和1两种元素,且所有的0都在1的左边,返回含有1数量最多的行,做法还是从右上角开始走
——————————————————————————————————————————
中级提升4
2:00 说这道题是在抄袭leetcode的洗衣机问题,每个洗衣机都有衣服,有衣服的洗衣机可以往左边扔衣服或者往右边仍衣服,为了把洗衣机中所有的衣服调整成一样多,最少需要几轮
比方说有三台机器,4 2 0 ,第一轮机器0往左扔一件衣服,第二轮机器1往左扔一件衣服,编程3 2 1 第二轮做同样的操作,编程 2 2 2 达到提议,所以最少需要2轮
我们可以算出一台机器的左右两侧的数据分布情况,如果两侧都少衣服,那么这个洗衣机需要的轮数就是两个相加,如果两侧都多衣服,那么就是两个之间取最大值(可以接受衣服),左负右正和左正右负都适用max(|左||右|),我们遍历每一个点的要求,找到其中最大的即为答案,整个数组中最痛的点解决了,其他的点一并解决
代码19:51 出自leetcode packing machine
26:00 以螺旋方式打印矩阵
我们要先写一个打印边框的函数,输入的是左上角点A和右下角点B的位置,然后A往右下移动 B往左上移动,A和B错过去了就停止
code 31:00
这道题就体现了宏观调度的使用,不必关注局部位置到底是该往哪个方向移动(确实比我在leetcode写的那个版本简单)
33:18 实现矩阵的顺时针转动,空间复杂度o(1)只能原地调整,不能使用额外的空间
我们还是在一个框中旋转,旋转的方式就是分组
52:00 以zigzag蛇形打印数组
就是斜线打印 代码在56:00
1:03
1:08 先说一个结论,如果n是一个质数,那么最少的操作数是只调操作2,因为想拼成质数,所以必须得用操作2,但是你最多只能调用一步操作1,一旦调用了两次及两次以上的操作1,那么结果就肯定不是质数了,会变成一个数的倍数
1:19 code ,这道题leetcode没有,可以直接去搜索这个题面
1:23 题目7 给定一个字符串数组arr,求出现次数最多的前K个
1:31 补充题目 ,用户需要实现一个结构,这个结构可以接受用户给的字符串,用户会调用一个功能是显示topk,怎么实现这两种功能
这道题的要求是手动写一个系统不能实现的堆结构
我们需要实现三大结构,第一个是词频表,第二个是堆,第三个是堆的位置map,这个map的key是字符串,value是其在堆上的位置。1:38开始讲如何使用这三种结构
代码1:48,2:05:34 heapify,2:05:32 heapinsert,heapify是从头节点往下滑,heapinsert是从尾节点往上浮
2:07:20,为什么不能使用系统提供的堆结构,系统提供的黑盒结构只提供输入一个自动排序,然后输出最大或者最小,不能提供堆结构的内部调整
———————————————————————————————————————————
中级提升班5
栈的程序设计题
建立一个data栈和一个最小栈,data栈按正常顺序压入数据,最小栈比较当前输入数据和最小栈数据的栈顶,谁小压入谁。弹出的时候data栈正常弹出(先进后出),最小栈也同步弹出
6:40 如何使用队列结构实现栈,如何使用栈结构实现队列
先说第二个,准备两个栈一个push,一个pop,传数据的时候全压入push栈,弹出的时候先把push栈的东西全部传入pop栈,再交由pop栈弹出。遵循的原则是 push栈弹出就全部弹出,同时pop栈有东西 push栈不要弹出,代码8:25
9:32,队列结构,准备两个队列,压入的时候正常压入一个队列,弹出的时候把最后一个数据之前的所有数传到另一个队列,把最后一个数据弹出
15:22 动态规划和空间压缩技巧,这个问题比较重要
假设我的动态规划任务是填写一张二维表,那么其实我只要使用一维数组,在数组内部做自我更新即可
29:43 应用场景
34:12 三维动态规划空间压缩
38:37
这个问题可以考虑成自己这个位置能留下多少水这个问题上
48:51 能不能不用辅助数组来记录左端最大值和右端最大值
56:37
先找到一个全局最大值,题目的结果一定是用这个全局最大值去减另外一个局部最大,因为这个全局最大值不是在左端区域就是在右端区域,假设在左端,我们需要让右端最大值尽可能小,如果在右端我们需要让左端最大值尽可能小。
例如我们让全局最大落在左半区,那么右半区肯定会有arr[n-1]这个数,如果继续扩充右半区,假设arr[n-2]小于arr[n-1]那么其实不改变右半区最大值,这是一次无效扩充,假设arr[n-2]大于arr[n-1]那么右半区最好不要扩充到n-2位置,因为这回导致右半区最大值变大,这不是我们想要的。综上,没有必要扩充右半区
1:03:19 旋转词
这题涉及到KMP算法,KMP算法的实质在于判断一个字符串是否是另一个字符串的子串,方法是把原字符串复制一份接到一起,看str2是不是str1的子串
1:07 咖啡杯问题
一个数组arr ,其实每个数字代表一个咖啡机需要多久泡一杯咖啡,另一个数字n,代表有多少个人等待喝咖,问怎么安排这些人让整个时间最省
准备一个包含三个元素的小根堆,key都是0,代表这台咖啡机从何时开始空闲,value就是每一台咖啡机的冲泡时间,假设数组arr = [2,3,7],那么小根堆会组织为(0,2),(0,3),(0,7),小根堆的排序方式是key+value最小的那个排在前面,相加代表使用在当前状况下,使用哪一台咖啡机会让冲泡最快结束。每使用一台咖啡机 元素会变化,如(0,2)变为(2,2)
1:22 还有一个进阶问题是,除了喝咖啡还有一个洗咖啡杯的问题,有两种洗法,一种是洗咖啡机 只有一个 每次时长为a,然后零一种就是自动挥发,需要b时,这里面有很巧妙的递归
1:49
把所有数字分成3类,1、奇数 2、包含一个2因子的数 3、其他(包含多个2因子,换句话说 包含4因子),然后转化为这几个数字的排列问题
———————————————————————————————————————————
中级提升班6
得到费波亚切数列,任意一项是前两项的和,怎么用logN的复杂度做到这个问题
规律:除了初始项,后面的每一项都有递归表达式的(且严格满足,没有条件转移),都能用logN解决,递推式里最小的数字是减几就是几阶行列式
重点重点,拿线性代数说事了,斐波那契数列是一个二阶问题,我们用初始状态把这个状态转移矩阵求出来,然后把问题转化为了,怎么样更快1的计算状态转移矩阵
16:09 怎么快速算幂,把幂次拆成二进制(可以使用数字>>一位然后与1相&&):每次固定和自己相乘,乘到特定的幂次才在结果中乘上这个数
23:26 code 29:45,算法过程举例,
40:00 牛生牛问题,48:00,兔生兔问题
例题
这种问题一看就是尝试打表法,就是输入是一个整数输出也是一个整数的问题,打表一看就符合斐波那契数列,然后就用logN来解了
1:00 原理解释
1:05
这看起来也像打表法的问题,其实斐波那契数列就有这种性质,数列中的任意3个数字都无法组成三角形
1:13:49 背包问题的变种
背包问题是数组中有一些数,每个数字只能使用一次,返回使用这些数恰好组成某个数的方法数,这道题的答案也在传统背包问题的状态转移表里
1:19:28
牛牛找工作问题
1:23 有序表解决问题,有序表按难度递增,同一难度报酬递减的顺序排列,然后删掉同一难度报酬少的那个,然后删掉难度递增报酬递减的那些,最后得到的就是难度递增报酬也递增,最后小伙伴在选的时候直接卡着边就行了
1:31
code 1:35 这种都是偏向业务的题,一个题解只能对应一道题在日常练习中没有用
重点在1:37 怎么把字符类型数字转成int型,注意要转成负的int型,负数的表示范围比正数大1
后面有代码精读,这里有一个防止溢出的逻辑,就是a=系统最小/10 b=系统最大%10,当前res不能比a小,否则*10就会溢出,如果当前res=a,那么要保证累加之后的其他位不能比b小。
———————————————————————————————————————————
中级提升 7
前缀树问题的解决方案,按路径建立好前缀树,前缀树的打印就是按照深度优先遍历来的
code10:00 前缀树不想二叉树,前缀树记录的是路径,二叉树记录的是节点
21:07 二叉树转化为双向链表
双向链表就是左端和右端都有双向箭头,code:24:39
30:00 找到一棵二叉树中最大的搜索二叉子树,并返回这个搜索二叉子树的头节点
递归的尝试套路:分两种情况,最大搜索子树和当前节点无关:需要左数返回最大二叉搜索子树的头,需要右树返回最大二叉搜索子树的头。最大搜索子树和当前节点有关:左数是搜索二叉树,右树是搜索二叉树,左max小于x,右min大于x
综上需要统一返回5个数,端头,是不是搜索二叉树,最大,最小,尺寸
47:00 code 这个代码看着太爽了!!
1:33:05 题目7 最大连续之和
用两个变量,一个叫cur,一个叫max
cur = cur+arr[i],如果cur变得比max更大了就更新max,如果cur小于0,就让cur回归为0,如果cur不小于0,就不改变cur,因为一旦结果小于0了,那下一个数肯定不想接收这个烂摊子,还是从头开始的好
1:54:50 给定一个矩阵,要求返回子矩阵的最大累加和,矩阵要求必须是长方形,压缩数组
算法的整体流程,两个for:
必须包含0行,且只包含0行的最大子矩阵0-0,必须包含0,1行,且只包含0,1行的最大子矩阵0-1,后续还有包含0,1,2行的0-2,0-3,1-1,1-2,1-3,2-2,2-3,3-3,然后把在同一列中的一行数据都加起来,变成上一道题
———————————————————————————————————————————
中级提升班-8
小明点路灯的问题
比如说有这样一个数组[X..X...XXX..X],X的位置是障碍物,我们需要把.的位置都点亮,至少需要多少盏路灯(路灯可以照亮左中右三个位置),那么这个数组至少需要3盏路灯才行
贪心方法
code 15:00,这个代码的潜台词是当前处理的点,没有被前面的灯影响到,基于这一点,所以在16行的代码中,如果当前来到的点是最后一个点,先放灯再退出,如果点后面连着点(23行的else),那就把灯放在index+1位置,然后直接跳到index+3去做判断,来维持当前位置不会被之前的灯影响到这一潜台词
24:25 给定一个二叉树的中序遍历和先序遍历,返回二叉树的后续遍历
code:26:30 先序遍历的顺序是中左右,中序遍历的顺序是左中右,后续遍历:左右中,那么先序遍历的第一个一定时后续遍历的最后一个,同时可以根据先序遍历头节点的位置,把中序遍历的数组分割成左数和右数。在左数中进行递归,还是进行上面的流程(递归函数的输入是数组范围),在右数中进行递归,进行上面的流程。截至条件就是先序遍历只有一个数字的话,直接填入后续遍历范围的最后一个位置。每次递归都只填写一个数字
50:00 数字转中文,英文表达
59:24 求完全二叉树的节点个数
遍历当然能做到这个事,但是怎么样才能把时间复杂度降低
首先求完全二叉树的深度,就是一直往左走,到叶节点返回。然后去右数的最左节点求一下深度,如果右数的最左节点到了最后一层,那么说明左数肯定是满二叉树(因为题中给出是完全二叉树)。那么左数的节点数是2^(n-1)-1,接下来只要递归的找右节点的个数就行了。
如果右数的左节点没到最后一层,那么就会到倒数第二层,且右数肯定是满的,所以右数的节点数就是2^(n-2)-1,接下来只要递归左数节点个数就行了,举例:1:05,讲解了递归过程,1:09:code
1:19 最长递增子序列问题
子序列是可以不连续的,比如输入[3,1,2,6,3,4],那么最长递增子序列就是[1,2,3,4]
1:31 之前讲了一个传统方法,时间复杂度是n平方的,后面接着讲了给优化方法,
假设arr的长度为6 [3 2 4 5 1 7],那么使用一个dp数组长度为6,里面记录了以当前位置结尾的最长递增子序列的值,还要使用一个长度为6的数组ends 里面记录了长度为i+1位置的子序列的最小结尾(i在0到5之间),每次先更新end,再更新dp,1:40原理,这道题很有通用性,建议熟悉
1:56 有序数列能不能整除3的问题
———————————————————————————————————————————
中级提升班9
给定一个整数数组长度为n,其中1<=A[i]<=n,对于[1,n]之内的元素,A数组中可能会重复出现,而且有些不会出现,需要用时间复杂度O(N),空间复杂度O(1)来解决这个问题
5:00 inplace算法流程,7:00 code,在理想状态下,每个数字都有,那么就是一个差值为1的等差数列,0位置放1,1位置放2,i位置放i+1。如果不是这样,假设5位置放16,那么就把这个16放在15位置上,如果15位置已经是16了,那么循环停止,如果15位置放的是3,那么就是把这个3放到2位置,周而复始。停止之后就能发现哪些位置上没有数字了
9:00 最少花多少钱给女主播打赏
一些递归过程跑不完可能是所有可能中递归条件不足,需要往里加一些递归条件
15:00 这里面就写一种错误的递归,这种递归是跑不完的
本来f(2)使用第一种掉成了f(4),但是f(4)调用第三种又变成了f(2),缺少basecase导致这个函数一直跑不完,办法就是找一个平凡解,比如一直使用第一种方法,单反在递归过程中发现一个已经花费的钱大于这个平凡解,那就停止递归。另外一个限制是,因为起始值和结束值都是偶数,所以不可能出现两倍的结尾值之后再往下减少的情况发生
24:00 最终版本,边界条件的确定:1、找平凡解2、在业务中找到不用再递归的条件
40:00 主播在固定时间内做活动获得的钱数最多,活动只能按照顺序。
我们为每一个节点生成一张只属于自己的有序表,这个有序表的key记录了从当前位置到完成任务所需要的天数,value记录走完这条路线需要挣的钱。然后把所有的表合在一起,最后删除掉那些天数递增钱数却递减的
1:00
题意就是给定一个序列,这个序列的二元运算两端都要加上小括号(二元运算就是与、或、亦或这三个),问总共有多少种加小括号的方式能达到最后bool类型的值 ,code:1:08,这个问题中,把序列里的每一个二元运算都当成最后一个,然后去判定为了得到最终的True或False,需要这最后一个二元表达式的左右两端需要什么样的返回值
1:20 上面这个问题怎么改动态规划,desire的状态只有T F两种,所以这是两张二维表,一张true表,一张false表,动态规划先确定变量的取值范围,然后根据观察递归过程,看有哪些变量是不需要填写的,有哪些变量是填好的。然后递归函数怎么写,表格就怎么填写
1:28 最长无重复子串,code:1:35
这种最长无重复字串或者子序列的问题,解法就是考虑以每一个点结尾的话可能性。思考这类动态规划的思路是,你在考虑如何得到第i个位置的值的时候,需要假设第i-1个位置的值已经填好了,那么根据i-1位置的信息就能得知,i位置的值不会超过a[i-1] +1,因为a[i-1]发现自己不能再往前推了,a[i]也不能再往前推。但是还需要确定字母i不在a[i-1]的这个范围里。
1:38 字符串替换的最小代价,图的宽度优先遍历和深度优先遍历
这道题根本没听,我不知道咋记录,而且还说年年出,都不不知道怎么设计出来的,但是挺重要的
2:00,code:2:09 leetcode第316题
老师代码是错的,需要把else里面的东西拿出来,整个放到if的前面。
先记录整个数组中各种类别的字母有几个,然后从左到右划定一个范围,一旦某一个范围的字母数量减少到0,那么就停止,在这个范围中执行两步操作:1.在这个范围里找到一个ASCII码最小的字母2、把这个字母左侧的所有数据都删除3、把这个字母右侧的所有相同类别字母都删除。从上面可以看出,这个范围保证了,左侧所有字符都删掉还能让所有字符类型都保留的范围,因为右侧只会删除同类型的字母,所以不会影响到其他类字母的数量
———————————————————————————————————————————
中级提升-10
从1:37开始 之前的题都讲过
所有子序列的排序先按照长度排序,子串互不重复,短的子序列排在长的子序列的前面,第二点,同意长度的子序列,字典序小的排在前面,然后回答某一个子序列是第几号,字符串是升序的
需要设计两个函数过程,f函数,在一个字符数组中,长度为n的子序列有多少个(不规定开头,包括所有26个字母开头之和)。g(x,y),以x字母开头,长度为y的子序列有多少个,code:1:40