- 找出前k高频元素,用构建小顶堆(可以用优先级队列,披着队列外衣的小顶堆)
- 栈适合作对称匹配、消除重复元素的问题
- 二叉树链式储存节点定义方式:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
- 链表节点定义方式:
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
- 二叉树遍历方式:深度优先(前中后序遍历,使用栈处理),广度优先(层序遍历,使用队列处理)
- 一般用左右孩子判断本节点的属性,判断左叶子节点(右叶子节点)需要通过父节点来判断
- 二叉树的最大深度就是根节点的高度,递归法用后序遍历,迭代法用层序遍历(记录层数即可),最小深度也用层序遍历
- 处理二叉搜索树时,首先要想到搜索树的特点,利用二叉搜索树的性质,最好使用递归法遍历
- 递归三部曲(传入参数,返回值,终止条件,单层逻辑)
- 回溯三部曲(回溯函数参数,终止条件,单层逻辑)
模板:
void backtracking(参数) {
if(终止条件){
存放结果;
return;
}
for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表);
回溯,撤销处理结果
}
}
注:递归和回溯对应,有递归就有一个回溯
- 回溯算法:
组合:组合问题、切割问题(能归为组合问题)、回文序列、子集问题、棋盘问题(N皇后、解数独(二维递归))
排列:不需要索引来控制一个集合里是否重复选取了,因为排列每次都是从头选取而且需要一个used数组来记录已经选取过的元素。
去重问题:需要对原数组排序,可以用used数组也可以用set来去重 - 贪心算法:巧妙,秘诀:局部最优推出全局最优,且没有反例,可以贪心
- 递归时间复杂度:递归的次数 * 每次递归中的操作次数
- 动态规划:一个问题有很多的重叠子问题优先考虑动态规划,由前面的状态可以推出后面的状态
步骤:dp数组定义以及下标含义、递推公式、初始化、遍历顺序、举例推导递推过程;
01背包(取或不取,只能放一个物件):理解01背包的模型(注意原模型是要把背包装满所获得最大价值),二维数组可以交换遍历顺序,一维滚动数组不能交换遍历顺序而且内循环背包重量从大到小倒序遍历;
完全背包(一个物件有无限多个):遍历顺序可以交换,背包重量从小到大正序遍历(这样才能把多个物件放入背包);
完全背包装满背包有多少种方法:完全背包求排列数、组合数的遍历顺序:如果求组合数就是外层for循环遍历物品,内层for遍历背包。如果求排列数就是外层for遍历背包,内层for循环遍历物品。
多重背包(每种物品最多M件):把M件展开就是01背包问题了; - 单调栈:寻找数组中任意元素的右边或者是左边第一个 比他大或者小的元素 用单调栈
比他大用递增栈(从栈顶到栈底),比他小用递减栈