Leetcode 刷题模板总结

 

二分查找法

二分查找法是一种时间复杂度为 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(路径, 选择列表);
        撤销选择;
    }
}

主要题型

  • 全排列:

    • 电话号码的字母组合

    • 括号生成

    • 全排列I
  • 子集:

    • 子集I
    • 子集II

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;
}

主要题目

  • 颜色分类

  • 数组中的第 k 个最大元素

 

你可能感兴趣的:(leetcode)