二叉树
654.最大二叉树
和之前根据 前中 、 中后构造二叉树是一样的思路
不要重新构造vector,用下表来解决。
注意 遇到如下情况应该是数组越界
617.合并二叉树
递归 中左右 迭代 和之前判断二叉树是否对称的写法类似
700.二叉搜索树中的搜索
二叉搜索树性质
98.验证二叉搜索树
注意 需要 左子树所有节点 < 中间 < 右子树所有节点
如下代码过不了这种情况
bool isValidBST(TreeNode* root) {
if(root == nullptr) return true;
if(root->left && root->val <= root->left->val) return false;
if(root->right && root->val >= root->right->val) return false;
return isValidBST(root->left) && isValidBST(root->right); }
需要记录左树最大值
530.二叉搜索树的最小绝对差
二叉搜索树的性质,可以转换为一个有序的数组,
或可以遍历的过程记录pre和root
501.二叉搜索树中的众数
与上一题类似,因为二叉搜索树的中序遍历是一个有序的数组
1.全部塞入数组,最后遍历数组
2.用pre来记录上一个节点,cur不等cout置为1,等就++,最后count与maxcount比较,
int maxcount = 0;
int count = 0;
TreeNode* pre = nullptr;
void traversal(TreeNode* cur,vector<int> &result){
if(cur == nullptr) return;
if(cur->left) traversal(cur->left, result); //左
//中
if(pre && cur->val == pre->val) count++; //相等++
else count = 1;
if(count == maxcount) result.push_back(cur->val); //相等放入结果集
if(count > maxcount){
maxcount = count;
result.clear(); //之前的结果均不满足,清除
result.push_back(cur->val);
}
pre = cur;
if(cur->right) traversal(cur->right, result); //右
}
236. 二叉树的最近公共祖先
后序遍历 左右中就是天然的回溯 有返回值,就需要left,right分开写
235. 二叉搜索树的最近公共祖先
二叉搜索树有序,相当于有方向,只要满足[p,cur,q],cur就是最近祖先
701.二叉搜索树中的插入操作
不考虑重构,找到空位置直接插入
450.删除二叉搜索树中的节点
key只有一个子树,直接返回
key两个子树都有,key->left插入到key->right最左边的子树上
669. 修剪二叉搜索树
巧用递归,搞清楚 不在区间内的情况:cur->val<low向上给递归(右树);cur->val > high,向上给递归(左树)。
108.将有序数组转换为二叉搜索树
与前序中序vector构造二叉树,注意区间
538.把二叉搜索树转换为累加树
递归:右中左遍历,利用pre做累加
124. 二叉树中的最大路径和
1.递归传递值 MAX(左,右)+中
2.max保存本节点的值 左+右+中
哈希表
454.四数相加II
与两数之和类似
1.map的key存A+B,value存次数
2.最后在map里找(0-(B+C))存在就count+=value
383. 赎金信
由于只有小写字符,直接用数组做哈希比较好,unordered_map开销比较大。
15. 三数之和
真滴难,卡尔哥给的方法非常巧妙 双指针重在去重 a+b+c = 0
- a 去重注意
nums[i] == nums[i+1]和nums[i] == nums[i-1]区别 前者直接漏掉[-1,-1,2] - bc去重注意位置,一定是已经得到结果的地方 开始就去重会少值
18. 四数之和
与上一题类似,就是不停去重,
1.用例[2,2,2,2,2] 8检查去重条件对不对
2.用例[1000000000,1000000000,1000000000,1000000000] 0,需要(long)
字符串
344.反转字符串
只用swap
541. 反转字符串II
在上一题基础上每次移动 i += 2*k格
题目:剑指Offer 05.替换空格
不用额外的辅助空间,先扩充,再分两个指针,从old和new的末尾分别遍历
151.翻转字符串里的单词
不用额外的辅助空间, 1.去掉多余空格,逻辑和27移除元素一致 2.反转 3.每个单词再反转
题目:剑指Offer58-II.左旋转字符串
利用反转的办法
28. 实现 strStr()
KMP,该来的还是来了,主要是next数组的写法
next[i]表示最长相等前缀后缀长度,利用next[j-1]进行回退
459.重复的子字符串
同样利用KMP算法,如果 next[len-1] != 0 有最长相等前缀后缀 && len % (len-next[len-1]) == 0 除的尽
回溯
回溯就是递归,回溯本质是暴力破解
思路
T backtracking(args) {
if (con) {
结尾;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
//有时需要先按照条件处理
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
注意T一般是void,遇到找见一条可行路径就返回的用bool
组合
77. 组合
回溯展开 优化:剪枝,剪枝没看懂
216.组合总和III
与77类似,增加了一个条件 剪枝也类似i <= n - (k - path.size()) + 1
17.电话号码的字母组合
1.先整一个const letterMap存数据
2.多组集合求组合
39. 组合总和
本题组合中的内容可以重复,迭代不用+1
40.组合总和II
难点在去重,去掉的是同一层的重,不去深度上的重 方案有二:\
- 利用一个全部初始化为false的used[]来标注,同一层的话为false,深度上为true,利用used源数组需要排序\
- 利用index
分割
131.分割回文串
基本思想一样,也是按照树形去划分
每次分割一段就看符不符合要求
93.复原IP地址
子集
78.子集
直接push到result数组里
90.子集II
不能重复,同### 40.组合总和II用used,原数组需要排序
491.递增子序列
不能重复且需要按需递增(不能排序),每一层用set来做
排列
46.全排列
全局used
47.全排列 II
再次考虑去重问题,排序,用used来做,有所不同的是这次 used[i-1] == true (剪去竖向)还是 used[i-1] == false (剪去横向)都能过
棋盘
51. N皇后
单层循环,主要是条件函数的书写,顺序是列、左上45度方向,左下135度方向判断
37. 解数独
多层循环,1.循环2.判断条件
找起始位置的方法应该是通用的:一段数组,每n(这里是3)个一组,给定任意的i,寻找离他最近分组的起始位置
int start = (i/3)*3;
332.重新安排行程
难在用unordered_map<string,map<string,int>> 即按照出发地字母有序的unordered_map<出发地,map<目的地,票数>>解决问题