Leetcode方法总结
数组/字符串⁍
区间问题⁍
- 数组不变,区间查询:前缀和、树状数组、线段树;
- 数组单点修改,区间查询:树状数组、线段树;
- 数组区间修改,单点查询:差分、线段树; ✔
- 数组区间修改,区间查询:线段树。
前缀和⁍
思路⁍
区间和 --》前缀和
- 定义 prefixSum 数组,prefixSum[x]:第 0 项到 第 x 项 的和。
$$prefixSum[x] = nums[0] + nums[1] +…+nums[x]$$ - nums 的某项 = 两个相邻前缀和的差:
$nums[x] = prefixSum[x] - prefixSum[x - 1]$ - nums 的 第 i 到 j 项 的和 ,有:
$$nums[i] +…+nums[j]=prefixSum[j] - prefixSum[i - 1]$$
例题⁍
2055. 蜡烛之间的盘子 (leetcode-cn.com)⁍
1 |
|
差分数组⁍
「差分」可以看做是求「前缀和」的逆向过程。
对于一个「 将区间$[l,r]$ 整体增加一个值$v$ 」操作,我们可以对差分数组$c$ 的影响看成两部分:
- 对 $c[l]+=v$ :由于差分是前缀和的逆向过程,这个操作对于将来的查询而言,带来的影响是对于所有的下标 大于等于 $l$ 的位置都增加了值 $v$ ;
- 对 $c[r+1]-=v$ :由于我们期望只对$[l,r]$产生影响,因此需要对下标大于$r$的位置进行减值操作,从而抵消“影响”。
对于最后的构造答案,可看做是对每个下标做“单点查询”操作,只需要 对差分数组求前缀和 即可。
例题⁍
1109. 航班预订统计 - 力扣(LeetCode) (leetcode-cn.com)
1 |
|
滑动窗口⁍
1 |
|
二分查找⁍
十分好用的二分查找法模板(Python 代码、Java 代码) - 简书 (jianshu.com)
找第一个大于target的数⁍
34. 在排序数组中查找元素的第一个和最后一个位置⁍
将问题转化为 找 target-1
和target
的最右侧值a和b,最后的区间是(a+1,b)。需要思考的是,此处的target-1
代表的是仅次于target
大小的数(也有可能是target-2之类的),故binarySearch
寻找的是第一个大于target
的数,接收完返回值只需-1
即可
注意细节(转化后的问题可以理解为35. 搜索插入位置)
1 |
|
回溯⁍
回溯法模板⁍
回溯法解决的问题都可以抽象为树形结构,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度。递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。
1 |
|
分类⁍
-
组合问题:N个数里面按一定规则找出k个数的集合
-
public void backtracking(int n, int k, int startIndex) { if (comb.size() == k) { res.add(new ArrayList<>(comb)); return; } for (int i = startIndex; i <= n - (k - comb.size()) + 1; i++) { comb.add(i); backtracking(n, k, i + 1); comb.removeLast(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- [切割问题](#切割问题):一个字符串按一定规则有几种切割方式
- 从startIndex循环,确定长度
切割条件的判断,不满足条件就continue
- [子集问题](#子集问题):一个N个数的集合里有多少符合条件的子集
- 组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点
- [排列问题](#排列问题):N个数按一定规则全排列,有几种排列方式
- 不需要startIndex,但是要去重,记录哪些元素用过了(?)
- [棋盘问题](#棋盘问题):N皇后,解数独等等
#### 去重
- 对于排序后的数组,有重复的话就去掉与上个一样的数
- ```java
for (int i = startIndex; i < nums.length; i++) {
if (i > startIndex && nums[i] == nums[i - 1]) { //去重
continue;
}
path.add(nums[i]);
backtracking(nums, i + 1);
path.removeLast();
}
-
-
记录有没有被访问过(注意在哪里更新visited表)
-
递增子序列
-
int[] visited = new int[201]; //记录数是否被访问过,访问过的(数+100)对应置1 for (int i = startIndex; i < nums.length; i++) { if ( !path.isEmpty() && nums[i] < path.getLast() || (visited[nums[i] + 100] == 1) ) { continue; } visited[nums[i] + 100] = 1; path.add(nums[i]); backtracking(nums, i + 1); path.removeLast(); } }
-
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 若叶!