1.双指针(前后/左右双指针)
1.1 283.移动零
- 快排双指针的核心算法
- 左边所有数 <= tmp,右边所有数 > tmp,以tmp这个数为标准
1.2 1089.复习零
- 如果一对双指针从左向右不行,那么就从右向左,换一个方向
1.3 202.快乐数
- 双指针中的快慢指针: slow+1,fast+2
1.4 11.最多盛水的容器
- 利用单调性
1.5 611.有效三角形个数
- 排序 + 固定一个指针(遍历) + 双指针
1.6 剑指 Offer 57. 和为s的两个数字
1.7 15. 三数之和
- 关键点: 去重 + 越界
1.8 18. 四数之和
- 比三数之和多了一层循环,注意: 数值大,需要使用long long
- long long aim = (long long)target - nums[fix1] - nums[fix2];
- int sum = nums[left]+nums[right];
2.滑动窗口(同向双指针)
2.1 209.长度最小的子数组
- left = 0,right = 0;
- 进窗口
- 判断
- 出窗口
- 更新结果(这个的顺序不一定)
2.2 3. 无重复字符的最长子串
2.3 1004.最大连续1的个数III
2.4 1658. 将 x 减到 0 的最小操作数
- 这题目的核心就是转换->正难则反
2.5 904.水果成篮
- 这题文字多,但很唬人,需要转换
2.6 438. 找到字符串中所有字母异位词
- 在这个滑动窗口中:窗口的大小没有变,算是一种特殊情况
2.7 30. 串联所有单词的子串
- 转换->找到字符串中所有字母异位词
- 注意:因为原数据是字符串,所以需要循环len次
2.8 76. 最小覆盖子串
-
int kinds = 0;//统计p的有效字符有多少种
-
int count= 0;//统计s的有效字符有多少种
- 进窗口->进入时,只有hash2[in] == hash1[in]时,count才会加1,但只要进入映射就会加1
- 出窗口->出去后,只有hash2[in] == hash1[in]时,count才会减1,但只要进入映射就会减1
3.二分查找(左端点 && 右端点)
只要有二段性就可以使用二分查找
朴素的二分模板
查找左边界的二分模板
查找右边界的二分模板
3.1 704. 二分查找
3.2 34. 在排序数组中查找元素的第一个和最后一个位置
- if(nums[left] != target){return {-1,-1};} 注意:考虑找不到的情况
3.3. 35. 搜索插入位置
- 结果在左端点
3.4 69. x 的平方根
3.5 852. 山脉数组的峰顶索引
- arr[mid] > arr[mid - 1] -> left = mid
- arr[mid] < arr[mid - 1] -> right = mid - 1;
3.6 162.寻找峰值
3.7 153. 寻找旋转排序数组中的最小值
- 这里我选择的是以D点作为参考点
- 如果选择A的则需要考虑其他情况(比如旋转n次,数组和原数组相等)
3.8 剑指 Offer 53 - II. 0~n-1中缺失的数字
- 注意特殊情况:[1],[0]时 return left == nums[left] ? left + 1 : left
只要有二段性就可以用二分法
4. 前缀和(动态规划)
4.1 【模板】前缀和
- 注意:这里需要开n+1个大小的数组,为了解决边界情况
4.2 【模板】二维前缀和
- 公式->看边界,在边界的点不变,其他-1
- 注意:这里需要开n+1个大小的数组,为了解决边界情况
4.3 724. 寻找数组的中心下标
- 注意:这里只需要开n个大小的数组,至于要开多大,需要具体问题具体分析
4.4 238. 除自身以外数组的乘积
4.5 560. 和为 K 的子数组
- 前缀和加入哈希表的时机?
- 在计算i位置之前,哈希表里面只保留[0,i-1]位置的前缀和,
所以在使用完之后再加入哈希表
- 在计算i位置之前,哈希表里面只保留[0,i-1]位置的前缀和,
- 不用真的创建一个前缀和数组?
- 用一个变量sum来标记前一个位置的前缀和
- 如果整个前缀和 等于 k呢?
- hash[0] = 1;
- 比如: [1, 2, 3] k = 3时,1和2等于3,然后结果3需要放入hash中,哈希表里面只保留[0,i-1]位置的前缀和
- 注意: 这题有正负,可能会在一段区间内相互抵消
4.6 974. 和可被 K 整除的子数组
- 这题的难点在:同余定理,负数修正 ,题意转换
4.7 525. 连续数组
- 这题也是需要前缀和 && 哈希表
- hash<int,int>中存的是前缀和 :下标
- 注意:hash[0] = -1;(默认前缀和为0的情况)
4.8 1314. 矩阵区域和
- 注意:映射关系
5. 位运算
常见位运算总结
1. 基础位运算
- << : 表示二进制向左移动
- >> : 表示二进制向右移动
- ~ : 表示二进制位按位取反
- & : 表示有0就是0
- | : 表示有1就是1
2. 给一个数n,确定它的二进制表示中的第x位是0,还是1
- n: 0 1 1 0 1 0 1 0 0 1
- (n >> x) & 1 ,结果是0则为0,是1则为1
3. 将一个数n的二进制表示的第x位修改成1
- n: 0 1 1 0 1 0 1 0 0 1
- n = n | (1 << x)
4. 将一个数n的二进制表示的第x为修改成0
- n: 0 1 1 0 1 0 1 0 0 1
- n = n & (~(1 << x))
5. 位图思想
- 位图的0和1也可以用来存有效信息
6. 提取一个数n二进制表示中最右侧的1(lowbit操作)
- n & -n
7. 干掉一个数(n) 二进制表示中最右侧的1
- n & (n - 1)
8. 位运算符的优先级
- 尽量能加括号,就加括号
9. 异或(^)运算符的运算律
- a ^ 0 = a
- a ^ a = 0
- a ^ b ^ c = a ^ (b ^ c)
5.1 面试题 01.01. 判定字符是否唯一
- 利用位图来解决,0表示没有出现这个字符,1表示出现了这个字符
- 注: len > 26,则必定会出现重复的字符
5.2 268. 丢失的数字
5.3 371. 两整数之和
- 两数之后的结果 = 无进位的二进制 + 有进位的二进制
- 需要一直循环直到 进位为0,
5.4 137. 只出现一次的数字II
- step1:依次修改ret中的每一位
-
step2:计算nums中所有的数的第i位的和,记得%3
5.5 面试题 17.19. 消失的两个数字
6. 模拟
6.1 1576. 替换所有的问号
- 只要保证?前,和?后的字符不和这个替换的字符一样就行了
6.2 495. 提莫攻击
6.3 6. N 字形变换
6.4 38. 外观数列
6.5 1419. 数青蛙
7. 分治 - 快速排序
三指针 + 交换 + (递归)
7.1 75. 颜色分类
7.2 912. 排序数组
7.3 215. 数组中的第K个最大元素
- 如果在递归过程中只有一个元素,则直接返回 这个值
7.4 LCR 159. 库存管理 III
- 这题和上面类似,但是这是找最小k个数,而不是一个数字
- 则排完序之后,不用返回第k个数
- 最后直接返回return {stock.begin(),stock.begin()+cnt};
8. 分治 - 归并排序
8.1 912. 排序数组
8.2 LCR 170. 交易逆序对的总数
- 逆序数 = 左边的逆序数 + 右边的逆序数 + 一左一右的逆序数
8.3 315. 计算右侧小于当前元素的个数
-
vector<int> tmp;// 记录临时数组
-
vector<int> tmp_index;// 记录临时数组下标
-
vector<int> index;// 记录数组下标
-
vector<int> ret;// 返回数组
8.4 493. 翻转对
- 这题和上一道题类似,但是需要先计算翻转对,再排序
9. 链表
9.1 2. 两数相加
- 双指针 + 头插法
- 小技巧: while(cur1 || cur2 || res)
9.2 24. 两两交换链表中的节点
- 只有当cur == null或next == null终止循环
9.3 143. 重排链表
- 找到链表的中间节点->快慢指针
- 再把后面的部分逆序->双指针(三指针),头插法
- 合并两个链表->双指针
9.4 25. K 个一组翻转链表
10. 哈希表
10.1 1. 两数之和
10.2 面试题 01.02. 判定是否互为字符重排
10.3 217. 存在重复元素
- 直接使用unordered_set来解决,注:这个容器的插入接口是insert
10.4 219. 存在重复元素 II
10.5 49. 字母异位词分组
11. 字符串
11.1 14.最长公共前缀
- 依次比较
11.2 5. 最长回文子串
11.3 67. 二进制求和
- 模拟列竖式运算
11.4 43. 字符串相乘
12. 栈
12.1 1047. 删除字符串中的所有相邻重复项
12.2 844. 比较含退格的字符串
12.3 227. 基本计算器 II
分情况讨论的过程
- 遇到操作符等,更新操作符op
- 遇到数字,看op
- op = "+",tmp直接入栈
- op= "-",-tmp入栈
- op="*",直接乘到栈顶元素
- op="/",直接和栈顶元素相除
12.4 394. 字符串解码
分情况讨论:
- 遇到数字: 提取这个数字,放入"数字栈"中
- 遇到"[":把后面的字符串提取出来,放入"字符串栈"中
- 遇到'']'',解析,然后放到''字符串栈''栈顶的字符串后面
- 遇到单独的字符,提取出来这个字符串,直接放在"字符串"栈顶的字符串后面
12.5 946. 验证栈序列
13. 队列 + 宽搜(BFS)
13.1 429. N 叉树的层序遍历
13.2 103. 二叉树的锯齿形层序遍历
13.3 662. 二叉树最大宽度
13.4 515. 在每个树行中找最大值
- 层序遍历, int tmp = INT _ MIN;//记录最大值,
14. 优先级队列(堆)
14.1 1046. 最后一块石头的重量
14.2 703. 数据流中的第 K 大元素
- 直接创建一个大小为k的小堆,栈顶就是我们需要的数据
14.3 692. 前K个高频单词
- 预处理一下原始字符数组->哈希表
- 创建一个大小为k的堆->小根堆,注:需要手动实现一个仿函数/类
- 循环
- 提取结果
14.4 295. 数据流的中位数
- 大小堆维护数据的中位数
===================以上内容均参考优选精品算法课(1~81)========================