常用算法模板

本文详细介绍了二分查找法、双指针技巧(同向、反向、快慢指针)、滑动窗口、广度优先搜索(BFS)与深度优先搜索(DFS)、各种排序算法(快速排序、归并排序、桶排序)、堆和并查集数据结构,以及链表反转的两种实现方法。
摘要由CSDN通过智能技术生成

1. Binary Search

二分查找法主要是解决在“一堆数中找出指定的数”这类问题。

想要应用二分查找法,这一堆数必须有以下特征:

存储在数组中

有序排列(无序的话二分用来猜答案的方法)

static int binarySearch(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) return mid;
        else if (nums[mid] > target) right = mid - 1;
        else left = mid + 1;
    }
    return -1;
}

LeetCode: 278, 410, 300, 1552, 1482, 1283, 1292

2. 双指针

同向双指针:283,1,16

反向双指针:11,75

快慢指针:142

quick sort,单调队列,单调栈,扫描线

3. Sliding window

340. 至多包含 K 个不同字符的最长子串:

public int lengthOfLongestSubstringKDistinct(String s, int k) {
    Map<Character, Integer> map = new HashMap();
    int left = 0, res = 0;
    for (int i = 0; i < s.length(); i++) {
        char cur = s.charAt(i);
        map.put(cur, map.getOrDefault(cur, 0) + 1);
        while (map.size() > k) {
            char c = s.charAt(left);
            map.put(c, map.get(left) - 1);
            left++;
        }
        res = Math.max(res, i - left + 1);
    }
    return res;
}

LeetCode: 209, 340

4. BFS + DFS

优缺点:

bfs: 对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费量大;

dfs: 对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速。

bfs:

// 计算从起点start到终点target的最近距离
int BFS(Node start, Node target) {
    Queue<Node> q;    // 核心数据结构
    Set<Node> visited;    // 避免走回头路

    q.offer(start);    // 将起点加入队列
    visited.add(start);
    int step = 0;    // 记录扩散的步数

    while (q not empty) {
        int sz = q.size();
        // 将队列中的所有节点向四周扩散
        for (int i = 0; i < sz; i++) {
            Node cur = q.poll();
            // 判断是否到达终点
            if (cur is target) 
                return step;
            // 将cur相邻的节点加入队列
            for (Node x : cur.adj())
                if (x not in visited) {
                    q.offer(x);
                    visited.add(x);
                }
        }
        // 更新步数
        step++;
    }
}

dfs:

result = []
def backtrack(路径, 选择列表):
    if 满足条件
        result.add(路径)
        return

    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

LeetCode: 102, 200, 490, 297, 124, 339

5. backtracking

类似dfs

LeetCode: 78, 17

6. sort

6.1 quick sort

public int[] quickSort(int[] array) {
    helper(array, 0, array.length - 1);
    return array;
}

private void helper(int[] array, int left, int right) {
    if (left >= right) return;
    int pivot = partition(array, left, right);
    helper(array, left, pivot - 1);
    helper(array, pivot + 1, right);
}

private int partition(int[] array, int left, int right) {
    int pivot = array[right], wall = left;
    for(int i = 0; i < array.length; i++) {
        if (array[i] < pivot) {
            swap(array, i, wall);
            wall++;
        }    
    }
    swap(array, wall, right);
    return wall;
}

LeetCode: 215

6.2 merge sort

public int[] mergeSort(int[] array) {
    return divide(array, 0, array.length - 1);
}

private int[] divide(int[] array, int start, int end) {
    if (left >= right) return new int[]{array[left]};
    int mid = start + (end - start) / 2;
    int[] leftResult = divide(array, start, mid);
    int[] rightResult = divide(array, mid + 1, end);
    return merge(leftResult, rightResult);
}

private int[] merge(int[] leftResult, int[] rightResult) {
    int[] res = new int[leftResult.length, right.length];
    int i = 0, j = 0, k = 0;
    while (i < leftResult.length && j < rightResult.length) {
        if (leftResult[i] < rightResult[j]) res[k++] = leftResult[i++];
        else res[k++] = rightResult[j++];
    }
    while (i < leftResult.length) res[k++] = leftResult[i++];
    while (j < rightResult.length) res[k++] = rightResult[j++];
    return res;
}

LeetCode: 23

6.3 bucket sort

void bucketSort(float[] a, int n) {
    for (each floating integer 'x' in n) {
        insert x into bucket[n * x];
    }
    for (each bucket) {
        sort(bucket);
    }
}

LeetCode: 451

7. 单调栈*

7.1 反向模板

public int[] nextGreaterElement1(int[] nums) {
    int n = nums.length, res[] = new int[n];
    Deque<Integer> stack = new ArrayDeque<Integer>();
    for (int = n - 1; i >= 0; i++) {
        while (!stack.isEmpty() && nums[i] >= stack.peek()) stack.pop();
        res[i] = stack.isEmpty() ? -1 : stack.peek();
        stack.push(nums[i]);
    }
    return res;
}

7.2 正向模板

 public int[] nextGreaterElement2(int[] nums) {
    int n = nums.length, res[] = new int[n];
    Deque<Integer> stack = new ArrayDeque();
    Arrays.fill(res, -1);
    for (int i = 0; i < n;, i++) {
        while (!stack.isEmpty() && nums[stack.peek()] < nums[i])
            res[stack.peek()] = nums[i];
        stack.push(i);
    }
    return res;
}

LeetCode: 42, 739

8. 单调队列*

队头删除不符合有效窗口的元素,队尾删除不符合最值的候选元素。

步骤:去尾,新元素入队,删头,取解

public int[] monotonicQueue(int[] nums, int k) {
    int N = nums.length;
    Deque<Integer> q = new ArrayDeque();
    int[] res = new int[N - k + 1];
    for (int i = 0; i < N; i++) {
        // 左出q,保证窗口大小k-1
        while (!q.isEmpty() && i - q.peekFirst() >= k) q.pollFirst();
        // 右出q,保证递减队列
        while (!q.isEmpty() && nums[q.peekLast()] <= nums[i]) q.pollLast();
        // 进q,此时q.size() == k
        q.offerLast(i);
        // 使用q左边最大值处理结果,可以在不同位置
        q.peekFirst();
    }
    return res;
}

LeetCode: 239, 862*

9. 扫描线

扫描线一般运用在图形上面,就是一条线在整个图上扫来扫去,一般用来解决图形面积,周长等问题。

public int minMeetingRooms(int[][] intervals) {
    List<int[]> list = new ArrayList();
    for (int[] interval : intervals) {
        list.add(new int[]{interval[0], 1});
        list.add(new int[]{interval[1], -1});
    }
    Collection.sort(list, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
    int res = 0, count = 0;
    for (int[] point : list) {
        count += point[1];
        res = Math.max(res, count);
    }
    return res;
}

LeetCode: 253, 252, 218

10. Trie(字典树)

字典树、前缀树,是一种多叉树结构;

1)根节点不包含字符,除根节点外的每一个节点都仅包含一个字符;

2)从根节点到某一节点路径上所经过的字符连接起来,即为该节点对应的字符串;

3)任意节点的所有子节点所包含的字符都不相同。

LeetCode: 208

class Trie {
    public Trie() {
    }

    TrieNode root = new TrieNode();
    
    public void insert(String word) {
        TrieNode node = root;
        for (char c : word) {
            if (node.children[c - 'a'] == null) 
                node.children[c - 'a'] = new TrieNode();
            node = node.children[c - 'a'];
 
        }
        node.isWord = true;    
    }
    
    public boolean search(String word) {
        TrieNode node = root;
        for (char c : word.toCharArray()) {
            if (node.children[c - 'a'] == null) return false;
            node = node.children[c - 'a'];
        }
        return node.isWord;
    }

    public boolean startWith(String prefix) {
        TrieNode node = root;
        for (char c : word.toCharArray()) {
            if (node.children[c - 'a'] == null) return false;
            node = node.children[c - 'a'];
        }
        return true;
    }
}

class TrieNode {
    TrieNode[] children = new TrieNode[26];
    boolean isWord;
}

LeetCode: 208, 212, 588

11. Heap(堆)

minHeap-PriorityQueue

class MyPriorityQueue {
    int q = new int[100];
    int size;
    
    public void offer(int num) {
        q[size] = num;
        siftUp(size++);
    }

    public int poll() {
        int val = q[0];
        q[0] = q[size - 1];
        size--;
        siftDown(0);
        return val;
    }

    public int peek() {
        return q[0];
    }

    private void siftUp(int cur) {
        if (cur != 0) {
            int parent = (cur - 1) / 2;
            if (q[parent]> q[cur]) {
                swap(parent, cur);
                siftUp(parent);
            }
        }
    }

    private void siftDown(int cur) {
        int min = cur;
        int left = cur * 2 + 1;
        int right = cur * 2 + 2;
        if (left < size && q[left] < q[min]) min = left;
        if (right < size && q[right] < q[min]) min = right;
        if (cur != min) {
            swap(cur, min);
            siftDown(min);
        }
    }

    private void swap(int i, int j) {
        int tmp = q[i];
        q[i] = q[j];
        q[j] = tmp;    
    }
}

12. Union find(并查集)

并查集是一种树形的数据结构,用于处理不交集的合并及查询问题。

Find: 确定元素属于哪一个自己;

Union: 将两个子集合并成同一个集合。

class DSU {
    int[] parent;
    
    public DSU(int N) {
        parent = new int[N];
        for (int i = 0; i < N; i++) parent[i] = i;
    }

    public int find(int x) {
        if (parent[x] != x) parent[x] = find(parent[x]);
        return parent[x];
    }

    public int union(int x, int y) {
        parent[find(x)] = find(y);
    }
}

LeetCode: 721

13. 链表

13.1 反转链表

// Iterator
public ListNode reverseList(ListNode head) {
    ListNode newHead = null;
    ListNode cur = head;
    while (cur != null) {
        ListNode next = cur.next;
        cur.next = newHead;
        newHead = cur;
        cur = next;
    }
    return newHead;
}

// Recursive
public ListNode reverseList(ListNode head) {
    return reverse(head, null);
}

private ListNode reverse(ListNode head, ListNode newHead) {
    if (head == null) return newHead;
    ListNode next = head.next;
    head.next = newHead;
    return reverse(next, head);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值