You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1494 lines
50 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

算法和数据结构体系学习班
00 算法和数据结构学前必看
内容:
算法和数据结构课程体系介绍
算法和数据结构学习路线
算法和数据结构学习方式推荐
算法和数据结构面试软技巧
同学们的各种答疑问题
01 时间复杂度、空间复杂度、对数器和二分法
内容:
评估算法优劣的核心指标
时间复杂度、空间复杂度、估算方式、意义
常数时间的操作
选择排序、冒泡排序、插入排序
最优解
对数器
二分法
题目:
选择排序及其对数器验证
冒泡排序及其对数器验证
插入排序及其对数器验证
有序数组中找到num
有序数组中找到>=num最左的位置
有序数组中找到<=num最右的位置
局部最小值问题
定义何为局部最小值:
arr[0] < arr[1]0位置是局部最小
arr[N-1] < arr[N-2]N-1位置是局部最小
arr[i-1] > arr[i] < arr[i+1]i位置是局部最小
给定一个数组arr已知任何两个相邻的数都不相等找到随便一个局部最小位置返回
02 异或运算、进一步认识对数器的重要性
内容:
异或运算的性质
异或运算的题目
题目:
不用额外变量交换两个数的值
不用额外变量交换数组中两个数的值
一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
怎么把一个int类型的数提取出二进制中最右侧的1来
一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
一个数组中有一种数出现K次其他数都出现了M次
已知M > 1K < M找到出现了K次的数
要求额外空间复杂度O(1)时间复杂度O(N)
03 单双链表、栈和队列、递归和Master公式、哈希表和有序表的使用和性能
内容:
单链表、双链表
栈、队列
递归的物理实质
评估递归复杂度的Master公式
哈希表的使用和性能
有序表的使用和性能
题目:
反转单链表、反转双链表
在链表中删除指定值的所有节点
用双链表实现栈和队列
用环形数组实现栈和队列
实现有getMin功能的栈
两个栈实现队列
两个队列实现栈
用递归行为得到数组中的最大值并用master公式来估计时间复杂度
哈希表和有序表使用的code展示
04 归并排序及其常见面试题
内容:
归并排序
题目:
归并排序的递归和非递归实现
在一个数组中,一个数左边比它小的数的总和,叫该数的小和
所有数的小和累加起来,叫数组小和
例子: [1,3,4,2,5]
1左边比1小的数没有
3左边比3小的数1
4左边比4小的数1、3
2左边比2小的数1
5左边比5小的数1、3、4、 2
所以数组的小和为1+1+3+1+1+3+4+2=16
给定一个数组arr求数组小和
在一个数组中任何一个前面的数a和任何一个后面的数b如果(a,b)是降序的,就称为降序对
给定一个数组arr求数组的降序对总数量
在一个数组中对于任何一个数num求有多少个(后面的数*2)依然<num返回总个数
比如:[3,1,7,0,2]
3的后面有10
1的后面有0
7的后面有02
0的后面没有
2的后面没有
所以总共有5个
05 归并排序面试题(续)、快速排序
内容:
再来一个归并排序面试题
荷兰国旗问题
快速排序1.0
快速排序2.0
快速排序3.0
题目:
给定一个数组arr两个整数lower和upper
返回arr中有多少个子数组的累加和在[lower,upper]范围上
Leetcode题目https://leetcode.com/problems/count-of-range-sum/
荷兰国旗问题的实现
快速排序从1.0到3.0的实现
快速排序的递归实现和非递归实现
code附加双向链表进行快速排序的code实现
06 比较器、堆结构、堆排序
内容:
比较器
堆结构
堆排序
建立大根堆的两种方式,从上到下、从下到上,及其复杂度分析
题目:
比较器使用的code展示
堆结构的实现
堆排序的实现
已知一个几乎有序的数组。几乎有序是指如果把数组排好顺序的话每个元素移动的距离一定不超过k
k相对于数组长度来说是比较小的。请选择一个合适的排序策略对这个数组进行排序。
07 和堆有关的面试题、加强堆结构
内容:
线段最大重合问题
加强堆的实现
题目:
给定很多线段,每个线段都有两个数[start, end]
表示线段开始位置和结束位置,左右都是闭区间
规定:
1线段的开始和结束位置一定都是整数值
2线段重合区域的长度必须>=1
返回线段最多重合区域中,包含了几条线段
加强堆的实现、注意点解析
做一个加强堆的题目给定一个整型数组int[] arr和一个布尔类型数组boolean[] op
两个数组一定等长假设长度为Narr[i]表示客户编号op[i]表示客户操作
arr= [3,3,1,2,1,2,5…
op = [T,T,T,T,F,T,F…
依次表示:
3用户购买了一件商品
3用户购买了一件商品
1用户购买了一件商品
2用户购买了一件商品
1用户退货了一件商品
2用户购买了一件商品
5用户退货了一件商品…
一对arr[i]和op[i]就代表一个事件:
用户号为arr[i]op[i] == T就代表这个用户购买了一件商品
op[i] == F就代表这个用户退货了一件商品
现在你作为电商平台负责人,你想在每一个事件到来的时候,
都给购买次数最多的前K名用户颁奖。
所以每个事件发生后,你都需要一个得奖名单(得奖区)。
得奖系统的规则:
1如果某个用户购买商品数为0但是又发生了退货事件
则认为该事件无效得奖名单和上一个事件发生后一致例子中的5用户
2某用户发生购买商品事件购买商品数+1发生退货事件购买商品数-1
3每次都是最多K个用户得奖K也为传入的参数
如果根据全部规则得奖人数确实不够K个那就以不够的情况输出结果
4得奖系统分为得奖区和候选区任何用户只要购买数>0
一定在这两个区域中的一个
5购买数最大的前K名用户进入得奖区
在最初时如果得奖区没有到达K个用户那么新来的用户直接进入得奖区
6如果购买数不足以进入得奖区的用户进入候选区
7如果候选区购买数最多的用户已经足以进入得奖区
该用户就会替换得奖区中购买数最少的用户(大于才能替换),
如果得奖区中购买数最少的用户有多个,就替换最早进入得奖区的用户
如果候选区中购买数最多的用户有多个,机会会给最早进入候选区的用户
8候选区和得奖区是两套时间
因用户只会在其中一个区域,所以只会有一个区域的时间,另一个没有
从得奖区出来进入候选区的用户,得奖区时间删除,
进入候选区的时间就是当前事件的时间可以理解为arr[i]和op[i]中的i
从候选区出来进入得奖区的用户,候选区时间删除,
进入得奖区的时间就是当前事件的时间可以理解为arr[i]和op[i]中的i
9如果某用户购买数==0不管在哪个区域都离开区域时间删除
离开是指彻底离开,哪个区域也不会找到该用户
如果下次该用户又发生购买行为,产生>0的购买数
会再次根据之前规则回到某个区域中,进入区域的时间重记
请遍历arr数组和op数组遍历每一步输出一个得奖名单
public List<List<Integer>> topK (int[] arr, boolean[] op, int k)
08 前缀树、不基于比较的排序(计数排序、基数排序)、排序算法的稳定性
内容:
前缀树
计数排序
基数排序
排序算法的稳定性
题目:
前缀树实现
计数排序
基数排序
09 排序算法大总结、链表及其相关面试题
内容:
排序算法总结
排序算法常见的坑
工程上对排序的常见改进
链表面试题的常见技巧
题目:
输入链表头节点,奇数长度返回中点,偶数长度返回上中点
输入链表头节点,奇数长度返回中点,偶数长度返回下中点
输入链表头节点,奇数长度返回中点前一个,偶数长度返回上中点前一个
输入链表头节点,奇数长度返回中点前一个,偶数长度返回下中点前一个
给定一个单链表的头节点head请判断该链表是否为回文结构
给定一个单链表的头节点head给定一个整数n将链表按n划分成左边<n、中间==n、右边>n
一种特殊的单链表节点类描述如下
class Node {
int value;
Node next;
Node rand;
Node(int val) { value = val; }
}
rand指针是单链表节点结构中新增的指针rand可能指向链表中的任意一个节点也可能指向null
给定一个由Node节点类型组成的无环单链表的头节点head请实现一个函数完成这个链表的复制
返回复制的新链表的头节点要求时间复杂度O(N)额外空间复杂度O(1)
10 链表相关面试题(续)、二叉树的常见遍历
内容:
单链表的相交节点系列问题
一种看似高效其实搞笑的节点删除方式
二叉树的中序、先序、后序遍历
题目:
给定两个可能有环也可能无环的单链表头节点head1和head2
请实现一个函数如果两个链表相交请返回相交的第一个节点。如果不相交返回null
要求如果两个链表长度之和为N时间复杂度请达到O(N)额外空间复杂度请达到O(1)
能不能不给单链表的头节点,只给想要删除的节点,就能做到在链表上把这个点删掉?
二叉树先序、中序、后序的递归遍历和递归序
二叉树先序、中序、后序的非递归遍历
11 二叉树常见面试题和二叉树的递归套路(上)
内容:
通过题目来熟悉二叉树的解题技巧
题目:
二叉树的按层遍历
二叉树的序列化和反序列化
N叉树如何通过二叉树来序列化、并完成反序列化
Leetcode题目https://leetcode.com/problems/encode-n-ary-tree-to-binary-tree/
打印二叉树的函数设计
求二叉树的最大宽度
求二叉树某个节点的后继节点
二叉树结构如下定义:
Class Node {
V value;
Node left;
Node right;
Node parent;
}
给你二叉树中的某个节点,返回该节点的后继节点
折纸问题
请把一段纸条竖着放在桌子上然后从纸条的下边向上方对折1次压出折痕后展开
此时折痕是凹下去的,即折痕突起的方向指向纸条的背面
如果从纸条的下边向上方连续对折2次压出折痕后展开
此时有三条折痕,从上到下依次是下折痕、下折痕和上折痕。
给定一个输入参数N代表纸条都从下边向上方连续对折N次
请从上到下打印所有折痕的方向。
N=1时打印: down
N=2时打印: down down up
12 二叉树常见面试题和二叉树的递归套路(中)
内容:
通过题目来熟悉二叉树的解题技巧
介绍二叉树的递归套路
1假设以X节点为头假设可以向X左树和X右树要任何信息
2在上一步的假设下讨论以X为头节点的树得到答案的可能性最重要
3列出所有可能性后确定到底需要向左树和右树要什么样的信息
4把左树信息和右树信息求全集就是任何一棵子树都需要返回的信息S
5递归函数都返回S每一棵子树都这么要求
6写代码在代码中考虑如何把左树的信息和右树信息整合出整棵树的信息
题目:
判断二叉树是不是搜索二叉树
判断二叉树是不是平衡二叉树
判断二叉树是不是满二叉树
给定一棵二叉树的头节点head返回这颗二叉树中最大的二叉搜索子树的大小
给定一棵二叉树的头节点head任何两个节点之间都存在距离返回整棵二叉树的最大距离
13 二叉树常见面试题和二叉树的递归套路(下)、贪心算法
内容:
二叉树递归套路继续实践
一道贪心算法从头到尾的完整做法
解决贪心题目的重要技巧,即对数器来验证脑洞
再次强调对数器的重要性
题目:
判断二叉树是不是完全二叉树(一般方法解决、递归套路解决)
给定一棵二叉树的头节点head返回这颗二叉树中最大的二叉搜索子树的头节点
给定一棵二叉树的头节点head和另外两个节点a和b返回a和b的最低公共祖先
派对的最大快乐值
员工信息的定义如下:
class Employee {
public int happy; // 这名员工可以带来的快乐值
List<Employee> subordinates; // 这名员工有哪些直接下级
}
公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树
树的头节点是公司唯一的老板,除老板之外的每个员工都有唯一的直接上级
叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外每个员工都有一个或多个直接下级
这个公司现在要办party你可以决定哪些员工来哪些员工不来规则
1.如果某个员工来了,那么这个员工的所有直接下级都不能来
2.派对的整体快乐值是所有到场员工快乐值的累加
3.你的目标是让派对的整体快乐值尽量大
给定一棵多叉树的头节点boss请返回派对的最大快乐值。
给定一个由字符串组成的数组strs必须把所有的字符串拼接起来返回所有可能的拼接结果中字典序最小的结果
14 贪心算法(续)、并查集
内容:
贪心算法继续实战
并查集详解
题目:
给定一个字符串str只由'X'和'.'两种字符构成
'X'表示墙,不能放灯,也不需要点亮;'.'表示居民点,可以放灯,需要点亮
如果灯放在i位置可以让i-1i和i+1三个位置被点亮
返回如果点亮str中所有需要点亮的位置至少需要几盏灯
一块金条切成两半,是需要花费和长度数值一样的铜板
比如长度为20的金条不管怎么切都要花费20个铜板一群人想整分整块金条怎么分最省铜板?
例如,给定数组{10,20,30}代表一共三个人整块金条长度为60金条要分成102030三个部分。
如果先把长度60的金条分成10和50花费60再把长度50的金条分成20和30花费50一共花费110铜板
但如果先把长度60的金条分成30和30花费60再把长度30金条分成10和20花费30一共花费90铜板
输入一个数组,返回分割的最小代价
一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲,给你每一个项目开始的时间和结束的时间
你来安排宣讲的日程,要求会议室进行的宣讲的场次最多,返回最多的宣讲场次
输入正数数组costs、正数数组profits、正数K和正数M
costs[i]表示i号项目的花费
profits[i]表示i号项目在扣除花费之后还能挣到的钱(利润)
K表示你只能串行的最多做k个项目
M表示你初始的资金
说明:每做完一个项目,马上获得的收益,可以支持你去做下一个项目,不能并行的做项目。
输出:最后获得的最大钱数
并查集的实现
15 并查集相关的常见面试题
内容:
通过解答实际出现的面试题来体会并查集的优势、熟悉并查集的使用
题目:
一群朋友中,有几个不相交的朋友圈
Leetcode题目https://leetcode.com/problems/friend-circles/
岛问题(递归解法 + 并查集解法 + 并行解法)
给定一个二维数组matrix里面的值不是1就是0上、下、左、右相邻的1认为是一片岛返回matrix中岛的数量
16 图及其与图相关的算法
内容:
图的表达方式
图的常见描述
图的宽度优先遍历
图的深度优先遍历
图的拓扑排序
最小生成树算法Kruskal
最小生成树算法Prim
单元最短路径算法Dijkstra
题目:
图的数据结构抽象
实现图的宽度优先遍历
实现图的深度优先遍历
三种方式实现图的拓扑排序
用并查集实现Kruskal算法
用堆实现Prim算法
实现Dijkstra算法用加强堆做更好的实现16节+17节一开始
17 用加强堆更好的实现Dijkstra算法、常见的递归
内容:
加强堆实现Dijkstra算法
递归的设计
常见的递归
题目:
打印n层汉诺塔从最左边移动到最右边的全部过程递归+非递归实现)
打印一个字符串的全部子序列
打印一个字符串的全部子序列,要求不要出现重复字面值的子序列
打印一个字符串的全部排列
打印一个字符串的全部排列,要求不要出现重复的排列
给定一个栈,请逆序这个栈,不能申请额外的数据结构,只能使用递归函数
18 暴力递归到动态规划(一)
内容:
讲述暴力递归和动态规划的关系
记忆化搜索
动态规划都可以由暴力递归改进过来,解决动态规划的套路
常见的尝试模型
设计尝试过程的原则
本节是暴力递归到动态规划的总纲(很重要)
后续的课都是在讲述这一系列的套路
题目:
假设有排成一行的N个位置记为1~NN一定大于或等于2
开始时机器人在其中的M位置上(M一定是1~N中的一个)
如果机器人来到1位置那么下一步只能往右来到2位置
如果机器人来到N位置那么下一步只能往左来到N-1位置
如果机器人来到中间位置,那么下一步可以往左走或者往右走;
规定机器人必须走K步最终能来到P位置(P也是1~N中的一个)的方法有多少种
给定四个参数 N、M、K、P返回方法数
给定一个整型数组arr代表数值不同的纸牌排成一条线
玩家A和玩家B依次拿走每张纸牌
规定玩家A先拿玩家B后拿
但是每个玩家每次只能拿走最左或最右的纸牌
玩家A和玩家B都绝顶聪明
请返回最后获胜者的分数
19 暴力递归到动态规划(二)
内容:
以18节为总纲
背包问题
记忆化搜索的一个很重要的注意点
通过面试题进一步强化动态规划的解题套路
题目:
背包问题
给定两个长度都为N的数组weights和valuesweights[i]和values[i]分别代表 i号物品的重量和价值
给定一个正数bag表示一个载重bag的袋子装的物品不能超过这个重量
返回能装下的最大价值
规定1和A对应、2和B对应、3和C对应...26和Z对应
那么一个数字字符串比如"111”就可以转化为:
"AAA"、"KA"和"AK"
给定一个只有数字字符组成的字符串str返回有多少种转化结果
给定一个字符串str给定一个字符串类型的数组arr出现的字符都是小写英文
arr每一个字符串代表一张贴纸你可以把单个字符剪开使用目的是拼出str来
返回需要至少多少张贴纸可以完成这个任务
例子str= "babac"arr = {"ba","c","abcd"}
ba + ba + c 3 abcd + abcd 2 abcd+ba 2
所以返回2
给定两个字符串str1和str2
返回这两个字符串的最长公共子序列长度
比如 str1 = “a12b3c456d”,str2 = “1ef23ghi4j56k”
最长公共子序列是“123456”所以返回长度6
20 暴力递归到动态规划(三)
内容:
以18节为总纲
通过面试题进一步强化动态规划的解题套路
题目:
给定一个字符串str返回这个字符串的最长回文子序列长度
比如 str = “a12b3c43def2ghi1kpm”
最长回文子序列是“1234321”或者“123c321”返回长度7
请同学们自行搜索或者想象一个象棋的棋盘,
然后把整个棋盘放入第一象限,棋盘的最左下角是(0,0)位置
那么整个棋盘就是横坐标上9条线、纵坐标上10条线的区域
给你三个 参数 xyk
返回“马”从(0,0)位置出发必须走k步
最后落在(x,y)上的方法数有多少种?
给定一个数组arrarr[i]代表第i号咖啡机泡一杯咖啡的时间
给定一个正数N表示N个人等着咖啡机泡咖啡每台咖啡机只能轮流泡咖啡
只有一台咖啡机一次只能洗一个杯子时间耗费a洗完才能洗下一杯
每个咖啡杯也可以自己挥发干净时间耗费b咖啡杯可以并行挥发
假设所有人拿到咖啡之后立刻喝干净,
返回从开始等到所有咖啡机变干净的最短时间
三个参数int[] arr、int Nint a、int b
21 暴力递归到动态规划(四)
内容:
以18节为总纲
通过面试题进一步强化动态规划的解题套路
题目:
给定一个二维数组matrix一个人必须从左上角出发最后到达右下角
沿途只可以向下或者向右走,沿途的数字都累加就是距离累加和
返回最小距离累加和
arr是货币数组其中的值都是正数。再给定一个正数aim。
每个值都认为是一张货币,
即便是值相同的货币也认为每一张都是不同的,
返回组成aim的方法数
例如arr = {1,1,1}aim = 2
第0个和第1个能组成2第1个和第2个能组成2第0个和第2个能组成2
一共就3种方法所以返回3
arr是面值数组其中的值都是正数且没有重复。再给定一个正数aim。
每个值都认为是一种面值,且认为张数是无限的。
返回组成aim的方法数
例如arr = {1,2}aim = 4
方法如下1+1+1+1、1+1+2、2+2
一共就3种方法所以返回3
arr是货币数组其中的值都是正数。再给定一个正数aim。
每个值都认为是一张货币,
认为值相同的货币没有任何不同,
返回组成aim的方法数
例如arr = {1,2,1,1,2,1,2}aim = 4
方法1+1+1+1、1+1+2、2+2
一共就3种方法所以返回3
给定5个参数NMrowcolk
表示在N*M的区域上醉汉Bob初始在(row,col)位置
Bob一共要迈出k步且每步都会等概率向上下左右四个方向走一个单位
任何时候Bob只要离开N*M的区域就直接死亡
返回k步之后Bob还在N*M的区域的概率
22 暴力递归到动态规划(五)
内容:
以18节为总纲
通过面试题进一步强化动态规划的解题套路
斜率优化技巧
题目:
给定3个参数NMK
怪兽有N滴血等着英雄来砍自己
英雄每一次打击,都会让怪兽流失[0~M]的血量
到底流失多少?每一次在[0~M]上等概率的获得一个值
求K次打击之后英雄把怪兽砍死的概率
arr是面值数组其中的值都是正数且没有重复。再给定一个正数aim。
每个值都认为是一种面值,且认为张数是无限的。
返回组成aim的最少货币数
给定一个正数n求n的裂开方法数
规定:后面的数不能比前面的数小
比如4的裂开方法有
1+1+1+1、1+1+2、1+3、2+2、4
5种所以返回5
23 暴力递归到动态规划(六)
内容:
以18节为总纲
通过面试题进一步强化动态规划的解题套路
位信息技巧
题目:
给定一个正数数组arr
请把arr中所有的数分成两个集合尽量让两个集合的累加和接近
返回最接近的情况下,较小集合的累加和
给定一个正数数组arr请把arr中所有的数分成两个集合
如果arr长度为偶数两个集合包含数的个数要一样多
如果arr长度为奇数两个集合包含数的个数必须只差一个
请尽量让两个集合的累加和接近
返回最接近的情况下,较小集合的累加和
N皇后问题是指在N*N的棋盘上要摆N个皇后
要求任何两个皇后不同行、不同列, 也不在同一条斜线上
给定一个整数n返回n皇后的摆法有多少种。 n=1返回1
n=2或32皇后和3皇后问题无论怎么摆都不行返回0
n=8返回92
24 窗口内最大值或最小值的更新结构
内容:
滑动窗口
窗口内最大值或最小值的更新结构
用题目来学习窗口内最大值或最小值的更新结构提供的便利性
题目:
窗口内最大值或最小值更新结构的实现
假设一个固定大小为W的窗口依次划过arr
返回每一次滑出状况的最大值
例如arr = [4,3,5,4,3,3,6,7], W = 3
返回:[5,5,5,4,6,7]
给定一个整型数组arr和一个整数num
某个arr中的子数组sub如果想达标必须满足sub中最大值 sub中最小值 <= num
返回arr中达标子数组的数量
加油站的良好出发点问题
动态规划中利用窗口内最大值或最小值更新结构做优化(难)
arr是货币数组其中的值都是正数。再给定一个正数aim。
每个值都认为是一张货币,
返回组成aim的最少货币数
注意:因为是求最少货币数,所以每一张货币认为是相同或者不同就不重要了
25 单调栈
内容:
单调栈的原理(无重复数+有重复数)
用题目来学习单调栈提供的便利性
题目:
单调栈实现(无重复数+有重复数)
给定一个只包含正数的数组arrarr中任何一个子数组sub
一定都可以算出(sub累加和 )* (sub中的最小值)是什么,
那么所有子数组中,这个值最大是多少?
给定一个非负数组arr代表直方图返回直方图的最大长方形面积
给定一个二维数组matrix其中的值不是0就是1返回全部由1组成的最大子矩形内部有多少个1面积
给定一个二维数组matrix其中的值不是0就是1返回全部由1组成的子矩形数量
26 单调栈相关的题目(续)、斐波那契数列的矩阵快速幂模型
内容:
再讲一个单调栈相关的面试题
斐波那契数列的矩阵快速幂模型详解
题目:
给定一个数组arr返回所有子数组最小值的累加和
斐波那契数列矩阵乘法方式的实现
台阶方法数问题
一个人可以一次往上迈1个台阶也可以迈2个台阶返回迈上N级台阶的方法数
奶牛生小牛问题
第一年农场有1只成熟的母牛A往后的每年
1每一只成熟的母牛都会生一只母牛
2每一只新出生的母牛都在出生的第三年成熟
3每一只母牛永远不会死
返回N年后牛的数量
给定一个数N想象只由0和1两种字符组成的所有长度为N的字符串
如果某个字符串任何0字符的左边都有1紧挨着认为这个字符串达标
返回有多少达标的字符串
用1*2的瓷砖把N*2的区域填满返回铺瓷砖的方法数
27 KMP算法
内容:
KMP算法
和KMP算法相关的面试题
题目:
KMP算法实现
给定两棵二叉树的头节点head1和head2返回head1中是否有某个子树的结构和head2完全一样
判断str1和str2是否互为旋转字符串
28 Manacher算法
内容:
Manacher算法
和Manacher算法相关的面试题
题目:
Manacher算法实现
给定一个字符串str只能在str的后面添加字符想让str整体变成回文串返回至少要添加几个字符
29 在无序数组中找到第K小的数、蓄水池算法
内容:
时间复杂度O(N)可以解决在无序数组中找到第K小的数这个经典的面试题
改写快排的partition方法
bfprt算法
蓄水池算法
题目:
在无序数组中找到第K小的数改写快排+bfprt
设计在无序数组中收集最大的前K个数字的算法根据不同的三个时间复杂度设计三个算法
给定一个无序数组arr中长度为N给定一个正数k返回top k个最大的数
不同时间复杂度三个方法:
1O(N*logN)
2O(N + K*logN)
3O(n + k*logk)
蓄水池算法实现
假设有一个源源吐出不同球的机器,
只有装下10个球的袋子每一个吐出的球要么放入袋子要么永远扔掉
如何做到机器吐出每一个球之后,所有吐出的球都等概率被放进袋子里
30 二叉树的Morris遍历
内容:
二叉树之前的遍历方式有空间浪费的问题
Morris遍历时间复杂度O(N)额外空间复杂度O(1),通过利用原树中大量空闲指针的方式,达到节省空间的目的
假设来到当前节点cur开始时cur来到头节点位置
1如果cur没有左孩子cur向右移动(cur = cur.right)
2如果cur有左孩子找到左子树上最右的节点mostRight
a.如果mostRight的右指针指向空让其指向cur
然后cur向左移动(cur = cur.left)
b.如果mostRight的右指针指向cur让其指向null
然后cur向右移动(cur = cur.right)
3cur为空时遍历停止
Morris遍历实现二叉树的先序、中序、后序遍历
题目:
Morris遍历的实现
给定一棵二叉树的头节点head求以head为头的树中最小深度是多少
31 线段树
内容:
线段树是一种支持范围整体修改和范围整体查询的数据结构
线段树解决的问题范畴:大范围信息可以只由左、右两侧信息加工出,而不必遍历左右两个子范围的具体状况
题目:
给定一个数组arr用户希望你实现如下三个方法
1void add(int L, int R, int V) : 让数组arr[L…R]上每个数都加上V
2void update(int L, int R, int V) : 让数组arr[L…R]上每个数都变成V
3int sum(int L, int R) :让返回arr[L…R]这个范围整体的累加和
怎么让这三个方法时间复杂度都是O(logN)
想象一下标准的俄罗斯方块游戏X轴是积木最终下落到底的轴线
下面是这个游戏的简化版:
1只会下落正方形积木
2[a,b] -> 代表一个边长为b的正方形积木积木左边缘沿着X = a这条线从上方掉落
3认为整个X轴都可能接住积木也就是说简化版游戏是没有整体的左右边界的
4没有整体的左右边界所以简化版游戏不会消除积木因为不会有哪一层被填满。
给定一个N*2的二维数组matrix可以代表N个积木依次掉落
返回每一次掉落之后的最大高度
Leetcode题目https://leetcode.com/problems/falling-squares/
32 IndexTree、AC自动机
内容:
IndexTree
1支持区间查询
2没有线段树那么强但是非常容易改成一维、二维、三维的结构
3只支持单点更新
AC自动机
解决在一个大字符串中,找到多个候选字符串的问题
1把所有匹配串生成一棵前缀树
2前缀树节点增加fail指针
3fail指针的含义如果必须以当前字符结尾当前形成的路径是str剩下哪一个字符串的前缀和str的后缀
拥有最大的匹配长度。fail指针就指向那个字符串的最后一个字符所对应的节点迷不迷听讲述
题目:
IndexTree在一维数组和二维数组上的实现
AC自动机的实现
33 与哈希函数有关的结构
内容:
哈希函数
哈希函数的应用
布隆过滤器
一致性哈希
题目:
原理讲述为主,面试只会聊设计,所以本节无题目
34 资源限制类题目的解题套路
内容:
布隆过滤器用于集合的建立与查询,并可以节省大量空间
一致性哈希解决数据服务器的负载管理问题
利用并查集结构做岛问题的并行计算
哈希函数可以把数据按照种类均匀分流
位图解决某一范围上数字的出现情况,并可以节省大量空间
利用分段统计思想、并进一步节省大量空间
利用堆、外排序来做多个处理单元的结果合并
题目:
32位无符号整数的范围是0~4,294,967,295
现在有一个正好包含40亿个无符号整数的文件
可以使用最多1GB的内存怎么找到出现次数最多的数
32位无符号整数的范围是0~4,294,967,295现在有一个正好包含40亿个无符号整数的文件
所以在整个范围中必然存在没出现过的数可以使用最多1GB的内存怎么找到所有未出现过的数
进阶:内存限制为 3KB但是只用找到一个没出现过的数即可
有一个包含100亿个URL的大文件假设每个URL占用64B请找出其中所有重复的URL
补充:某搜索公司一天的用户搜索词汇是海量的(百亿数据量)请设计一种求出每天热门Top100词汇的可行办法
32位无符号整数的范围是0~4294967295现在有40亿个无符号整数可以使用最多1GB的内存找出所有出现了两次的数
32位无符号整数的范围是0~4294967295现在有40亿个无符号整数可以使用最多3K的内存怎么找到这40亿个整数的中位数
32位无符号整数的范围是0~4294967295有一个10G大小的文件每一行都装着这种类型的数字
整个文件是无序的给你5G的内存空间请你输出一个10G大小的文件就是原文件所有数字排序的结果
35 有序表(上)
内容:
平衡搜索二叉树
左旋
右旋
AVL树的节点违规4种类型LLLRRLRR
题目:
AVL树的实现
36 有序表(中)
内容:
size-balanced-tree详解
skiplist详解
聊聊红黑树
题目:
size-balanced-tree实现
skiplist实现
37 有序表(下)
内容:
讲解有序表相关的面试题
讲解改写有序表的题目核心点
题目:
给定一个数组arr和两个整数a和ba<=b。求arr中有多少个子数组累加和在[a,b]这个范围上。返回达标的子数组数量
有一个滑动窗口:
1L是滑动窗口最左位置、R是滑动窗口最右位置一开始LR都在数组左侧
2任何一步都可能R往右动表示某个数进了窗口
3任何一步都可能L往右动表示某个数出了窗口
想知道每一个窗口状态的中位数
设计一个结构包含如下两个方法:
void add(int index, int num)把num加入到index位置
int get(int index) 取出index位置的值
void remove(int index) 把index位置上的值删除
要求三个方法时间复杂度O(logN)
假设有打乱顺序的一群人站成一个队列数组people表示队列中一些人的属性不一定按顺序
每个people[i]=[hi, ki]表示第i个人的身高为hi前面正好有ki个身高大于或等于hi的人
请你重新构造并返回输入数组people所表示的队列返回的队列应该格式化为数组queue
其中queue[j]=[hj, kj]是队列中第j个人的属性queue[0] 是排在队列前面的人)。
Leetcode题目https://leetcode.com/problems/queue-reconstruction-by-height/
38 根据对数器找规律、根据数据量猜解法
内容:
讲解对数器找规律的解题技巧
讲解根据数据量猜解法的技巧
1C/C++1秒处理的指令条数为10的8次方
2Java等语言1~4秒处理的指令条数为10的8次方
3这里就有大量的分析提示了
题目:
小虎去买苹果,商店只提供两种类型的塑料袋,每种类型都有任意数量
1能装下6个苹果的袋子
2能装下8个苹果的袋子
小虎可以自由使用两种袋子来装苹果,但是小虎有强迫症,他要求自己使用的袋子数量必须最少,
且使用的每个袋子必须装满给定一个正整数N返回至少使用多少袋子。如果N无法让使用的每个袋子必须装满返回-1
给定一个正整数N表示有N份青草统一堆放在仓库里有一只牛和一只羊牛先吃羊后吃它俩轮流吃草
不管是牛还是羊每一轮能吃的草量必须是141664…(4的某次方)
谁最先把草吃完谁获胜假设牛和羊都绝顶聪明都想赢都会做出理性的决定。根据唯一的参数N返回谁会赢
定义一种数:可以表示成若干(数量>1连续正数和的数
比如5=2+35就是这样的数12=3+4+512就是这样的数
2=1+12不是这样的数因为等号右边不是连续正数
给定一个参数N返回是不是可以表示成若干连续正数和的数
int[] dd[i]i号怪兽的能力
int[] pp[i]i号怪兽要求的钱
开始时你的能力是0你的目标是从0号怪兽开始通过所有的怪兽。
如果你当前的能力小于i号怪兽的能力你必须付出p[i]的钱,贿赂这个怪兽,然后怪兽就会加入你
他的能力直接累加到你的能力上如果你当前的能力大于等于i号怪兽的能力
你可以选择直接通过,你的能力并不会下降,你也可以选择贿赂这个怪兽,然后怪兽就会加入你
他的能力直接累加到你的能力上
返回通过所有的怪兽,需要花的最小钱数
(课上会给出不同的数据量描述)
39 根据数据量猜解法(续)、分治技巧、卡特兰数
内容:
继续熟悉根据数据量猜解法
讲解分治法
讲解卡特兰数课上证明的时候有小错在40节开始处修正了
题目:
给定一个非负数组arr和一个正数m返回arr的所有子序列中累加和%m之后的最大值
牛牛家里一共有n袋零食, 第i袋零食体积为v[i]背包容量为w牛牛想知道在总体积不超过背包容量的情况下,
一共有多少种零食放法体积为0也算一种放法
1 <= n <= 30, 1 <= w <= 2 * 10^9v[I] (0 <= v[i] <= 10^9
假设给你N个0和N个1你必须用全部数字拼序列返回有多少个序列满足任何前缀串1的数量都不少于0的数量
有N个二叉树节点每个节点彼此之间无任何差别返回由N个二叉树节点组成的不同结构数量是多少
题目补充: arr中的值可能为正可能为负可能为0自由选择arr中的数字能不能累加得到sum多种做法
40 子数组达到规定累加和的最大长度系列问题、矩阵处理技巧题
内容:
修正了39节卡特兰数讲解时的一个小错误
熟悉子数组达到规定累加和的三个模型正、有正有负有0、累加和<=K
矩阵处理技巧的宏观调度coding技巧
题目:
给定一个正整数组成的无序数组arr给定一个正整数值K找到arr的所有子数组里哪个子数组的累加和等于K
并且是长度最大的,返回其长度
给定一个整数组成的无序数组arr值可能正、可能负、可能0给定一个整数值K
找到arr的所有子数组里哪个子数组的累加和等于K并且是长度最大的返回其长度
给定一个整数组成的无序数组arr值可能正、可能负、可能0给定一个整数值K
找到arr的所有子数组里哪个子数组的累加和<=K并且是长度最大的返回其长度
给定一个数组arr给定一个值v求子数组平均值小于等于v的最长子数组长度
给定一个正方形矩阵matrix原地调整成顺时针90度转动的样子
给定一个正方形或者长方形矩阵matrix实现转圈打印
给定一个正方形或者长方形矩阵matrix实现zigzag打印
转圈打印星号*问题
41 四边形不等式技巧(上)
内容:
区间划分问题中的划分点不回退现象
四边形不等式技巧特征
1两个可变参数的区间划分问题
2每个格子有枚举行为
3当两个可变参数固定一个另一个参数和答案之间存在单调性关系
4而且两组单调关系是反向的(升 升,降 降) (升 降,降 升)
5能否获得指导枚举优化的位置对上+右,或者,左+下
四边形不等式技巧注意点
1不要证明用对数器验证
2枚举的时候面对最优答案相等的时候怎么处理用对数器都试试
3可以把时间复杂度降低一阶
O(N^3) -> O(N^2)
O(N^2 * M) -> O(N * M)
O(N * M^2) -> O(N * M)
4四边形不等式有些时候是最优解有些时候不是
不是的原因:尝试思路,在根儿上不够好
题目:
给定一个非负数组arr长度为N
那么有N-1种方案可以把arr切成左右两部分
每一种方案都有min{左部分累加和,右部分累加和}
求这么多方案中min{左部分累加和,右部分累加和}的最大值是多少?
整个过程要求时间复杂度O(N)
把题目一中提到的min{左部分累加和,右部分累加和}定义为S(N-1),也就是说:
S(N-1)在arr[0…N-1]范围上做最优划分所得到的min{左部分累加和,右部分累加和}的最大值
现在要求返回一个长度为N的s数组
s[i] =在arr[0…i]范围上做最优划分所得到的min{左部分累加和,右部分累加和}的最大值
得到整个s数组的过程做到时间复杂度O(N)
摆放着n堆石子。现要将石子有次序地合并成一堆规定每次只能选相邻的2堆石子合并成新的一堆
并将新的一堆石子数记为该次合并的得分求出将n堆石子合并成一堆的最小得分或最大得分合并方案
给定一个整型数组 arr数组中的每个值都为正数表示完成一幅画作需要的时间再给定一个整数num
表示画匠的数量,每个画匠只能画连在一起的画作
所有的画家并行工作,返回完成所有的画作需要的最少时间
arr=[3,1,4]num=2。
最好的分配方式为第一个画匠画3和1所需时间为4
第二个画匠画4所需时间为4
所以返回4
arr=[1,1,1,4,3]num=3
最好的分配方式为第一个画匠画前三个1所需时间为3
第二个画匠画4所需时间为4
第三个画匠画3所需时间为3
返回4
42 四边形不等式技巧(下)
内容:
继续熟悉四边形不等式
展示好的尝试是最关键的
题目:
一条直线上有居民点,邮局只能建在居民点上
给定一个有序正数数组arr每个值表示 居民点的一维坐标,再给定一个正数 num表示邮局数量
选择num个居民点建立num个邮局使所有的居民点到最近邮局的总距离最短返回最短的总距离
arr=[1,2,3,4,5,1000]num=2
第一个邮局建立在3位置第二个邮局建立在1000位置
那么1位置到邮局的距离为22位置到邮局距离为13位置到邮局的距离为04位置到邮局的距离为15位置到邮局的距离为2
1000位置到邮局的距离为0
这种方案下的总距离为6其他任何方案的总距离都不会比该方案的总距离更短所以返回6
一座大楼有0~N层地面算作第0层最高的一层为第N层
已知棋子从第0层掉落肯定不会摔碎从第i层掉落可能会摔碎也可能不会摔碎(1≤i≤N)
给定整数N作为楼层数再给定整数K作为棋子数
返回如果想找到棋子不会摔碎的最高层数,即使在最差的情况下扔的最少次数
一次只能扔一个棋子
N=10K=1
返回10
因为只有1棵棋子所以不得不从第1层开始一直试到第10层
在最差的情况下即第10层是不会摔坏的最高层最少也要扔10次
N=3K=2
返回2
先在2层扔1棵棋子如果碎了试第1层如果没碎试第3层
N=105K=2
返回14
第一个棋子先在14层扔碎了则用仅存的一个棋子试1~13
若没碎第一个棋子继续在27层扔碎了则用仅存的一个棋子试15~26
若没碎第一个棋子继续在39层扔碎了则用仅存的一个棋子试28~38
若没碎第一个棋子继续在50层扔碎了则用仅存的一个棋子试40~49
若没碎第一个棋子继续在60层扔碎了则用仅存的一个棋子试51~59
若没碎第一个棋子继续在69层扔碎了则用仅存的一个棋子试61~68
若没碎第一个棋子继续在77层扔碎了则用仅存的一个棋子试70~76
若没碎第一个棋子继续在84层扔碎了则用仅存的一个棋子试78~83
若没碎第一个棋子继续在90层扔碎了则用仅存的一个棋子试85~89
若没碎第一个棋子继续在95层扔碎了则用仅存的一个棋子试91~94
若没碎第一个棋子继续在99层扔碎了则用仅存的一个棋子试96~98
若没碎第一个棋子继续在102层扔碎了则用仅存的一个棋子试100、101
若没碎第一个棋子继续在104层扔碎了则用仅存的一个棋子试103
若没碎第一个棋子继续在105层扔若到这一步还没碎那么105便是结果
43 状态压缩的动态规划
内容:
动态规划的状态压缩技巧
题目:
在"100 game"这个游戏中两名玩家轮流选择从1到10的任意整数累计整数和
先使得累计整数和达到或超过100的玩家即为胜者如果我们将游戏规则改为 “玩家不能重复使用整数” 呢?
例如两个玩家可以轮流从公共整数池中抽取从1到15的整数不放回直到累计整数和 >= 100
给定一个整数 maxChoosableInteger 整数池中可选择的最大数和另一个整数 desiredTotal累计和
判断先出手的玩家是否能稳赢(假设两位玩家游戏时都表现最佳)
你可以假设 maxChoosableInteger 不会大于 20 desiredTotal 不会大于 300。
Leetcode题目https://leetcode.com/problems/can-i-win/
TSP问题
有N个城市任何两个城市之间的都有距离任何一座城市到自己的距离都为0
所有点到点的距离都存在一个N*N的二维数组matrix里也就是整张图由邻接矩阵表示
现要求一旅行商从k城市出发必须经过每一个城市且只在一个城市逗留一次最后回到出发的k城
参数给定一个matrix给定k。返回总距离最短的路的距离
铺砖问题最优解其实是轮廓线dp但是这个解法对大厂刷题来说比较难掌握课上的解法即可
你有无限的1*2的砖块要铺满M*N的区域
不同的铺法有多少种?
44 DC3生成后缀数组详解
内容:
后缀数组
介绍用DC3算法生成后缀数组的流程
题目:
给你一个字符串 s找出它的所有子串并按字典序排列返回排在最后的那个子串
Leetcode题目https://leetcode.com/problems/last-substring-in-lexicographical-order/
DC3算法的实现完全根据论文描述
45 后缀数组解决的面试题
内容:
通过题目进一步熟悉DC3算法
通过DC3算法得到height数组
题目:
给定两个字符串str1和str2想把str2整体插入到str1中的某个位置形成最大的字典序返回字典序最大的结果
给两个长度分别为M和N的整型数组nums1和nums2其中每个值都不大于9再给定一个正数K。 你可以在nums1和nums2中挑选数字要求一共挑选K个并且要从左到右挑。返回所有可能的结果中代表最大数字的结果
最长公共子串问题是面试常见题目之一假设str1长度Nstr2长度M
一般在面试场上回答出O(N*M)的解法已经是比较优秀了
因为得到O(N*M)的解法,就已经需要用到动态规划了
但其实这个问题的最优解是O(N+M),需要用到后缀数组+height数组
课上将对本题解法代码进行详解
46 动态规划猜法中和外部信息简化的相关问题(上)、哈夫曼树
内容:
以18节做总纲
有些动态规划面试题,需要很好的设计参数,这种设计方式都有"外部信息简化"的特征
哈夫曼树
题目:
有n个气球编号为0到n-1每个气球上都标有一个数字这些数字存在数组nums中
现在要求你戳破所有的气球。戳破第i个气球你可以获得nums[i - 1] * nums[i] * nums[i + 1] 枚硬币
这里的i-1和i+1代表和i相邻的、没有被戳爆的两个气球的序号
如果i-1或i+1超出了数组的边界那么就当它是一个数字为1的气球
求所能获得硬币的最大数量
Leetcode题目https://leetcode.com/problems/burst-balloons/
给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色,你将经过若干轮操作去去掉盒子
直到所有的盒子都去掉为止每一轮你可以移除具有相同颜色的连续k个盒子k >= 1
这样一轮之后你将得到 k * k 个积分,当你将所有盒子都去掉之后,求你能获得的最大积分和
Leetcode题目https://leetcode.com/problems/remove-boxes/
如果一个字符相邻的位置没有相同字符,那么这个位置的字符出现不能被消掉
比如:"ab"其中a和b都不能被消掉
如果一个字符相邻的位置有相同字符,就可以一起消掉
比如:"abbbc"中间一串的b是可以被消掉的消除之后剩下"ac"
某些字符如果消掉了,剩下的字符认为重新靠在一起
给定一个字符串,你可以决定每一步消除的顺序,目标是请尽可能多的消掉字符,返回最少的剩余字符数量
比如:"aacca", 如果先消掉最左侧的"aa",那么将剩下"cca",然后把"cc"消掉,剩下的"a"将无法再消除返回1
但是如果先消掉中间的"cc",那么将剩下"aaa"最后都消掉就一个字符也不剩了返回0这才是最优解。
再比如:"baaccabb"
如果先消除最左侧的两个a剩下"bccabb"如果再消除最左侧的两个c剩下"babb"最后消除最右侧的两个b剩下"ba"无法再消除返回2
而最优策略是:
如果先消除中间的两个c剩下"baaabb"如果再消除中间的三个a剩下"bbb"最后消除三个b不留下任何字符返回0这才是最优解
给定一个数组arr和一个正数M返回在arr的子数组在长度不超过M的情况下最大的累加和
哈夫曼树的实现
47 动态规划猜法中和外部信息简化的相关问题、最大网络流算法之Dinic算法
内容:
进一步解决带有"外部信息简化"特征的动态规划
Dinic算法
题目:
有台奇怪的打印机有以下两个特殊要求:
打印机每次只能打印由同一个字符组成的序列。
每次可以在任意起始和结束位置打印新字符,并且会覆盖掉原来已有的字符。
给你一个字符串s你的任务是计算这个打印机打印它需要的最少打印次数。
Leetcode题目https://leetcode.com/problems/strange-printer/
整型数组arr长度为n(3 <= n <= 10^4),最初每个数字是<=200的正数且满足如下条件
1. 0位置的要求arr[0]<=arr[1]
2. n-1位置的要求arr[n-1]<=arr[n-2]
3. 中间i位置的要求arr[i]<=max(arr[i-1],arr[i+1])
但是在arr有些数字丢失了比如k位置的数字之前是正数丢失之后k位置的数字为0
请你根据上述条件计算可能有多少种不同的arr可以满足以上条件
比如 [6,0,9] 只有还原成 [6,9,9]满足全部三个条件所以返回1即[6,9,9]达标
Dinic算法详解
测试链接https://lightoj.com/problem/internet-bandwidth