二分查找法
二分查找法是一种时间复杂度为 O(logN) 的算法,它通常应用在排过序的数组上。它的算法思想是,每次用 O(1) 的时间减少一半的搜索区间。
二分查找法有三种实现方式,但我偏爱第三种,因为它基本可以适用于所有题目,不用再为边界条件而苦恼。
做二分法的题目首先要明白题目需要我们找的是第一次/最后一次/任意出现的 target 的位置。
模板
public int binarySearch(int[] nums, int target) {
if (nums == null || nums.length == 0) return -1;
int start = 0, end = nums.length - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (nums[mid] == target) end = mid;
// if (nums[mid] == target) start = mid;
else if (nums[mid] < target) start = mid;
else end = mid;
}
if (nums[start] == target) return start;
if (nums[end] == target) return end;
// if (nums[end] == target) return end;
// if (nums[start] == target) return start;
return -1;
}
注:以上是寻找第一次 target 出现的位置的模板;注释是寻找最后一次 target 出现的模板。
主要题目
-
制作m束花所需要的最少天数 (第一次)
-
搜索插入位置 (第一次)
回溯法
回溯法是一种特殊的深度优先搜索算法(DFS), 做该类题目的要点在于画出深度优先搜索树,然后确定相应的路径和可选列表。
模板
List<.> res = new ArrayList<>();
public void backtrack(路径, 可选列表) {
if (满足结束条件) {
加入 res;
return;
}
for (选择 : 选择列表) {
做出选择;
backtrack(路径, 选择列表);
撤销选择;
}
}
主要题型
DFS 和 BFS
深度优先搜索(DFS) 和 广度优先搜索(BFS) 是两个最常见的搜索算法。
模板(DFS)
public void dfs(Graph G, int v) {
marked[v] = true; // 将 v 结点标记为已访问
for (int w : G.adj(v)) { // 遍历与 v 相邻的结点
if (!marked[w]) {
dfs(G, w); // 递归访问
}
}
}
模板(BFS)
public void bfs(Graph G, int s) {
q.offer(s); // 先将源加入队列
marked[s] = true; // 标记为已访问
while (!q.isEmpty()) {
int v = q.poll();
for (int w : G.adj(v)) { // 遍历 v 的相邻结点
if (!marked[w]) { // 当 v 的相邻结点 w 合法
queue.offer(w); // 将 w 加入
marked[w] = true; // 标记为已访问
}
}
}
}
主要题目
快排相关
此类题目会利用普通快速排序中的 partition 函数。
模板
private int partition(int[] nums, int lo, int hi) {
int i = lo, j = hi + 1;
while (true) {
while (nums[++i] < nums[lo]) if (i == hi) break;
while (nums[--j] > nums[lo]) if (j == lo) break;
if (i >= j) break;
exch(nums, i, j);
}
exch(nums, lo, j);
return j;
}
注意:进入此 partition 函数的时候需要保证 lo 严格小于 hi。
优点: 简单;
缺点:在于如果数组中缺失值比较多时,时间复杂度较大。
另一种 partition 函数主要利用了三路快排中的 partition 函数。(一般建议使用该函数,灵活性更强)
private int partition(int[] a, int lo, int hi) {
int lt = lo, gt = hi;
int v = a[lo];
int i = lo;
while (i <= gt) {
if (a[i] < v) exch(a, lt++, i++);
else if (a[i] > v) exch(a, i, gt--);
else i++;
}
return lt;
}
主要题目