算法和数据结构体系学习班 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 > 1,K < 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)依然=1 返回线段最多重合区域中,包含了几条线段 加强堆的实现、注意点解析 做一个加强堆的题目,给定一个整型数组,int[] arr;和一个布尔类型数组,boolean[] op 两个数组一定等长,假设长度为N,arr[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> topK (int[] arr, boolean[] op, int k) 08 前缀树、不基于比较的排序(计数排序、基数排序)、排序算法的稳定性 内容: 前缀树 计数排序 基数排序 排序算法的稳定性 题目: 前缀树实现 计数排序 基数排序 09 排序算法大总结、链表及其相关面试题 内容: 排序算法总结 排序算法常见的坑 工程上对排序的常见改进 链表面试题的常见技巧 题目: 输入链表头节点,奇数长度返回中点,偶数长度返回上中点 输入链表头节点,奇数长度返回中点,偶数长度返回下中点 输入链表头节点,奇数长度返回中点前一个,偶数长度返回上中点前一个 输入链表头节点,奇数长度返回中点前一个,偶数长度返回下中点前一个 给定一个单链表的头节点head,请判断该链表是否为回文结构 给定一个单链表的头节点head,给定一个整数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 subordinates; // 这名员工有哪些直接下级 } 公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树 树的头节点是公司唯一的老板,除老板之外的每个员工都有唯一的直接上级 叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外每个员工都有一个或多个直接下级 这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则: 1.如果某个员工来了,那么这个员工的所有直接下级都不能来 2.派对的整体快乐值是所有到场员工快乐值的累加 3.你的目标是让派对的整体快乐值尽量大 给定一棵多叉树的头节点boss,请返回派对的最大快乐值。 给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有可能的拼接结果中字典序最小的结果 14 贪心算法(续)、并查集 内容: 贪心算法继续实战 并查集详解 题目: 给定一个字符串str,只由'X'和'.'两种字符构成 'X'表示墙,不能放灯,也不需要点亮;'.'表示居民点,可以放灯,需要点亮 如果灯放在i位置,可以让i-1,i和i+1三个位置被点亮 返回如果点亮str中所有需要点亮的位置,至少需要几盏灯 一块金条切成两半,是需要花费和长度数值一样的铜板 比如长度为20的金条,不管怎么切都要花费20个铜板,一群人想整分整块金条,怎么分最省铜板? 例如,给定数组{10,20,30},代表一共三个人,整块金条长度为60,金条要分成10,20,30三个部分。 如果先把长度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~N,N一定大于或等于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和values,weights[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条线的区域 给你三个 参数 x,y,k 返回“马”从(0,0)位置出发,必须走k步 最后落在(x,y)上的方法数有多少种? 给定一个数组arr,arr[i]代表第i号咖啡机泡一杯咖啡的时间 给定一个正数N,表示N个人等着咖啡机泡咖啡,每台咖啡机只能轮流泡咖啡 只有一台咖啡机,一次只能洗一个杯子,时间耗费a,洗完才能洗下一杯 每个咖啡杯也可以自己挥发干净,时间耗费b,咖啡杯可以并行挥发 假设所有人拿到咖啡之后立刻喝干净, 返回从开始等到所有咖啡机变干净的最短时间 三个参数:int[] arr、int N,int 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个参数,N,M,row,col,k 表示在N*M的区域上,醉汉Bob初始在(row,col)位置 Bob一共要迈出k步,且每步都会等概率向上下左右四个方向走一个单位 任何时候Bob只要离开N*M的区域,就直接死亡 返回k步之后,Bob还在N*M的区域的概率 22 暴力递归到动态规划(五) 内容: 以18节为总纲 通过面试题进一步强化动态规划的解题套路 斜率优化技巧 题目: 给定3个参数,N,M,K 怪兽有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或3,2皇后和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 单调栈 内容: 单调栈的原理(无重复数+有重复数) 用题目来学习单调栈提供的便利性 题目: 单调栈实现(无重复数+有重复数) 给定一个只包含正数的数组arr,arr中任何一个子数组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个最大的数 不同时间复杂度三个方法: 1)O(N*logN) 2)O(N + K*logN) 3)O(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) 3)cur为空时遍历停止 Morris遍历实现二叉树的先序、中序、后序遍历 题目: Morris遍历的实现 给定一棵二叉树的头节点head,求以head为头的树中,最小深度是多少? 31 线段树 内容: 线段树是一种支持范围整体修改和范围整体查询的数据结构 线段树解决的问题范畴:大范围信息可以只由左、右两侧信息加工出,而不必遍历左右两个子范围的具体状况 题目: 给定一个数组arr,用户希望你实现如下三个方法 1)void add(int L, int R, int V) : 让数组arr[L…R]上每个数都加上V 2)void update(int L, int R, int V) : 让数组arr[L…R]上每个数都变成V 3)int 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指针 3)fail指针的含义:如果必须以当前字符结尾,当前形成的路径是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种类型(LL,LR,RL,RR) 题目: AVL树的实现 36 有序表(中) 内容: size-balanced-tree详解 skiplist详解 聊聊红黑树 题目: size-balanced-tree实现 skiplist实现 37 有序表(下) 内容: 讲解有序表相关的面试题 讲解改写有序表的题目核心点 题目: 给定一个数组arr,和两个整数a和b(a<=b)。求arr中有多少个子数组,累加和在[a,b]这个范围上。返回达标的子数组数量 有一个滑动窗口: 1)L是滑动窗口最左位置、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 根据对数器找规律、根据数据量猜解法 内容: 讲解对数器找规律的解题技巧 讲解根据数据量猜解法的技巧 1)C/C++,1秒处理的指令条数为10的8次方 2)Java等语言,1~4秒处理的指令条数为10的8次方 3)这里就有大量的分析提示了 题目: 小虎去买苹果,商店只提供两种类型的塑料袋,每种类型都有任意数量 1)能装下6个苹果的袋子 2)能装下8个苹果的袋子 小虎可以自由使用两种袋子来装苹果,但是小虎有强迫症,他要求自己使用的袋子数量必须最少, 且使用的每个袋子必须装满,给定一个正整数N,返回至少使用多少袋子。如果N无法让使用的每个袋子必须装满,返回-1 给定一个正整数N,表示有N份青草统一堆放在仓库里,有一只牛和一只羊,牛先吃,羊后吃,它俩轮流吃草 不管是牛还是羊,每一轮能吃的草量必须是:1,4,16,64…(4的某次方) 谁最先把草吃完,谁获胜,假设牛和羊都绝顶聪明,都想赢,都会做出理性的决定。根据唯一的参数N,返回谁会赢 定义一种数:可以表示成若干(数量>1)连续正数和的数 比如,5=2+3,5就是这样的数;12=3+4+5,12就是这样的数 2=1+1,2不是这样的数,因为等号右边不是连续正数 给定一个参数N,返回是不是可以表示成若干连续正数和的数 int[] d,d[i]:i号怪兽的能力 int[] p,p[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^9,v[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位置到邮局的距离为2,2位置到邮局距离为1,3位置到邮局的距离为0,4位置到邮局的距离为1,5位置到邮局的距离为2 1000位置到邮局的距离为0 这种方案下的总距离为6,其他任何方案的总距离都不会比该方案的总距离更短,所以返回6 一座大楼有0~N层,地面算作第0层,最高的一层为第N层 已知棋子从第0层掉落肯定不会摔碎,从第i层掉落可能会摔碎,也可能不会摔碎(1≤i≤N) 给定整数N作为楼层数,再给定整数K作为棋子数 返回如果想找到棋子不会摔碎的最高层数,即使在最差的情况下扔的最少次数 一次只能扔一个棋子 N=10,K=1 返回10 因为只有1棵棋子,所以不得不从第1层开始一直试到第10层 在最差的情况下,即第10层是不会摔坏的最高层,最少也要扔10次 N=3,K=2 返回2 先在2层扔1棵棋子,如果碎了试第1层,如果没碎试第3层 N=105,K=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长度N,str2长度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