东哥的算法小抄——笔记(题解整理)

第一章 数据结构

三、二叉树

4. 序列化

[297] 二叉树的序列化与反序列化
DFS:
中序的反序列化不能用,因为不能确定root是左子树和右子树中间的哪一位。前序和后序可以写,后序是反过来写,因为能发现,根节点在最后面,反过来的话,就是根、右、左。

BFS:
层级遍历用到queue,因为queue可以前出后进,序列化和反序列化都用到queue,一个逻辑,取出父节点的同时放入两子节点。
未完

5. 后序

[652] 寻找重复子树
后序遍历能复原子树模样,序列化成字符串好比较不同子树,使用一个map放所有子树字符串,一个vector放符合答案的结点。

6. 归并排序

[912] 排序数组
归并排序:两个链表里各放一个指针,比较,谁小拿出来排队,然后指针后移。
一句话总结了归并排序:先把左半边数组排好序,再把右半边数组排好序,然后把两半数组合并。

[315] 计算右侧小于当前元素的个数
和[912]题类似,唯一区别在于vector tmp使用的是vector>类型,second位置放的是每个数的初始位置,为了写答案的时候定位。使用一个vector ans传回答案。

7. 搜索树BST(特性篇)

BST的中序遍历结果是升序的。

[230] 二叉搜索树中第K小的元素
解法并不是最高效的解法,而是仅仅适用于这道题。

[538] 把二叉搜索树转换为累加树

二叉树的通用思路:思考每个节点干什么。
BST问题的思考方向:1. 利用BST左小右大的特性。2. 利用中序遍历即升序的特性。

8. 搜索树BST(基操篇)

[98] 验证二叉搜索树
如果是正常的思路,每次验证只能管自己的左右子树,管不了孙子树,所以参数设置max,min传下去,就可以约束。

[700] 二叉搜索树中的搜索
ok

[701] 二叉搜索树中的插入操作
不要用return,return还要判断是左还是右,这种直接返回在=号后侧可以直接赋值。

[450] 删除二叉搜索树中的节点
删除的三种情况,最后一种:有左子树和右子树,需要找到右子树最小的结点,value赋值过去,然后删除这个最小结点即可(左子树同理,移动最大的结点)。

//二叉搜索树的模板
void BST(TreeNode root, int target) {
    if (root.val == target)
        // 找到目标,做点什么
    if (root.val < target) 
        BST(root.right, target);//root.right=BST(root.right, target);这种也可以
    if (root.val > target)
        BST(root.left, target);
}

9. 搜索树BST(构造篇)

[96] 不同的二叉搜索树
有更简单的方法。。此方法也是老方法,除了增加一二维vector记录,防止重复计算。

[95] 不同的二叉搜索树 II
与题【96】不同之处在于如何保存每次配好的子树,反正我想了很久没想出来。

10. 快速排序的正确理解方式及运用

一句话快速排序:是先将一个元素排好序,然后再将剩下的元素排好序;是一个构造二叉搜索树的过程。
但是二叉搜索树有不平衡的风险,最极端是编程一个链表,都排到一边去了。

  1. 使用洗牌算法
  2. partition函数中随机选择数组元素作为分界点

[912] 排序数组
总共分三步,1、选择打乱方式,此处推荐两种(1.每次都随机选(这个方法) 2.洗牌算法随机打乱都可以)。2、选择low位置数值为大小分隔数。3、i在前,j在后,相对移动,移动到两者大小都不符合的时候交换。4、在分割好的两区重新上述方法。
二叉树的视角,类似于前序遍历,最后排出来一个BST。

[215] 数组中的第K个最大元素
在【912】的基础上,用if else左右筛选,再return即可。
还有二叉堆的方法,到时候再写。

11. 题目不让我做什么,我就偏要去做什么

[341] 扁平化嵌套列表迭代器
有趣的一道题,有时间不看题解自己写。有两个方法:
在递归方法中,我们在遍历时如果遇到一个嵌套的 子list,就立即处理该 子list,直到全部展开;
在迭代方法中,我们不需要全部展开,只需要把 当前list 的所有元素放入 list 中。
题中NestedInteger是多叉树的结构,考察的显然是迭代,所以考虑在next还是hasnext函数中展开时,不太懂,参考负雪明烛。
注意stack特性,逆序放进去。

12. Git原理之最近公共祖先

[236] 二叉树的最近公共祖先
几种情况,一种是q,p一左一右,一种是q就是俩人的公共祖先。框架是前序加后序这样。

[1644] 二叉树的最近公共祖先 II
使用两个bool来记录判断是否量元素都存在,而不是用nullptr来判断利用后序的原理,先判断两条子树是否存在元素,然后再判断root本身是否=目标,这样子能做到不遗漏,如果先判断root,正确就返回了,两条子树还没有查,产生了漏洞。

[235] 二叉搜索树的最近公共祖先
前面好像有几个题解标了BST,但是其实不是的,我看看。这道题很巧,只要root在两个元素之间,就是最近祖先了。

1650. 二叉树的最近公共祖先 III
单链表的内容,没写

13. 完全二叉树的节点数,你真的会算吗?

[222] 完全二叉树的节点个数
结合了普通二叉树和满二叉树,不是复杂的结合,而是判断是不是满二叉树,不是的话用普通二叉树的法子解决(每一层如此)。

四、图

1. 图论算法基础

[797] 所有可能的路径
没啥好说的,可以重新写一下看看,离开的时候要pop

2. 环检测算法及拓扑排序

。。。

五、数据结构

3. 前缀树算法模板秒杀 5 道算法题

什么叫做query本身是键的情况?

关于回溯算法框架标准多叉树框架的区别,关键在于遍历「节点」和遍历「树枝」的区别。由于 Trie 树将字符存储在「树枝」上,traverse函数是在遍历树枝上的字符,所以采用的是回溯算法框架。

回溯算法类似于深度遍历DFS,节点有值的时候,就增加结果,但是也不能放弃节点孩子的可能性,直到节点为null,然后返回上一层,再进行深入遍历。

api种,有几个和前缀相关的,有几个不和前缀相关的。
感觉hasKeyWithPatternkeysWithPattern复杂多了,因为has的话只要找到就返回,返回路径感觉复杂一些,而收集keys就简单一些。

[1804] 实现 Trie (前缀树) II-remove函数-countWordsStartingWith函数-重写
这道题不容易啊,如果是直接用labuladong的模板,就会产生冗杂,速度慢的,虽然道理是很正的,但是代码量太多了,找时间重写一遍,参考其他人答案。每个函数思路已在题中写出。

[211] 添加与搜索单词
用了两个api,一个经典insert,还有一个是通配符,稍微复杂一点

[648] 单词替换-={nullptr}-
用了trie的两个api,insert完全照搬,prefix类似查找最短prefix。可以直接在private里初始化

[208] 实现 Trie (前缀树)-this-指针数组
三个功能都很类似,主要是设置成员变量,一个指针数组和一个布尔变量,有时间复现一下labuladong的思路。

[677] 键值映射-类似1804-看1804即可

4. 啊这,一道找中位数的算法题把东哥整不会了…

[295] 数据流的中位数
数组,查找简单,插入难,搬移数据要O(N);
链表,查找难也是ON,插入容易;
平衡二叉树介于两者之间,增删改查都是logn,但是放不了重复元素;
优先级队列,有一个排序,但是只能在堆顶查找删除,在队伍中间拿不了元素。

很巧妙的一道题,比上一章节前缀树的所有api操作要好理解,将排序切割成两个优先队列,中位数在队列之间找,或者计算出来。

5. 单调栈解题模板及运用

单调栈用途不广泛,只适用于下一个更大元素这种类型

[496] 下一个更大元素 I-unordered_map-stack-hashmap[num]
找到下一个更大元素,使用单调栈(大概是唯一适配),保存元素,没有重复元素,所以应该联想到哈希表

739 题「每日温度」:
这一道题我以前写过

6. 单调队列通用模板及运用

题目写过,暂时不看这章

7. 图文详解二叉堆,实现优先级队列

二叉堆是特殊的二叉树,是通过数组构成的,分为上浮和下沉两个操作。
delmax是把头尾内容交换,删除尾节点,然后头结点下沉。insert是在尾节点插入,然后上浮。

8. 数据结构设计:用栈实现队列/用队列实现栈

队列和栈的底层都是链表和数组构成。所以两者可以互相表示,只是限于api的不同。
用两个栈实现队列,头对头,正常push,若要pop,导入到另一个栈中,再pop。

队列实现栈(无亮点):push简单,pop的话,队头的

9. 设计 Twitter:合并 k 个有序链表和面向对象设计

还没有看

第二章 动态规划

一、动态规划基本技巧

1. 动态规划解题套路框架

最重要:写出动态转移方程
斐波那契是自顶向下,动态规划是自底向上,一般脱离递归,通过迭代实现
凑零钱问题(最优子结构):子问题之间必须独立
记住重复子问题有两种方法:1、dp数组(自底向上,开头的0位可能是base case) 2、备忘录(可能就是递归,自顶向下)

2. 最长递增子序列教你推导状态转移方程

[300] 最长递增子序列-dp数组-O(N^2)
两个for循环,dp数组里放得是,以i位数结尾的最长子序列的长度,所以,先是和前面所有位比较是否能成为末尾,其次在当末尾里,哪一队最长,记下长度,即可。
二分查找法(了解即可,所以我没看)

3. 动态规划答疑篇

都是一些基础技巧,暂时不想看。直接一边写题,不懂了再看
。。。。还有几篇

二、子序列类型问题

1. 经典动态规划:编辑距离

[72] 编辑距离-dp数组
用的dp数组,自底向上,for循环一个一个网上推。

用的递归,备忘录,hashmap,(还没写完)

2. 二维递增子序列:信封嵌套问题

你可能感兴趣的:(算法,算法)