跳至主要內容

最长上升子序列(LIS)

大约 3 分钟

最长上升子序列(LIS)

题目难度
300. 最长递增子序列open in new window中等
354. 俄罗斯套娃信封问题open in new window困难
1713. 得到子序列的最少操作次数open in new window困难
2111. 使数组 K 递增的最少操作次数open in new window困难
2407. 最长递增子序列 IIopen in new window困难
题目难度
435. 无重叠区间open in new window中等
646. 最长数对链open in new window中等
452. 用最少数量的箭引爆气球open in new window中等
1691. 堆叠长方体的最大高度open in new window困难三维 俄罗斯套娃信封问题 但是 O(n^2)
面试题 08.13. 堆箱子open in new window困难类似 1691
960. 删列造序 IIIopen in new window困难

模板(严格递增)

func lengthOfLIS(nums []int) int {
    g := []int{}
    for _, x := range nums {
        j := sort.SearchInts(g, x)
        if j == len(g) { // >=x 的 g[j] 不存在
            g = append(g, x)
        } else {
            g[j] = x
        }
    }
    return len(g)
}

300. 最长递增子序列

import java.util.ArrayList;
import java.util.List;

public class Solution300 {
    // 动态规划
    // 时间复杂度 O(n^2)
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        // 定义 dp[i] 为包含第 i 个元素的最长上升子序列长度
        int[] dp = new int[n];
        dp[0] = 1;
        int max = 1;
        for (int i = 1; i < n; i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                // 严格递增
                if (nums[i] > nums[j]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            max = Math.max(max, dp[i]);
        }
        return max;
    }

    // 贪心 + 二分查找
    // 时间复杂度 O(nlogn)
    public int lengthOfLIS2(int[] nums) {
        List<Integer> a = new ArrayList<>();
        for (int x : nums) {
            int j = searchInts(a, x);
            if (j == a.size()) a.add(x);
            else a.set(j, x);
        }
        return a.size();
    }

    private int searchInts(List<Integer> a, int key) {
        int l = 0, r = a.size();
        while (l < r) {
            int m = l + (r - l) / 2;
            if (a.get(m) >= key) r = m;
            else l = m + 1;
        }
        return l;
    }
}

354. 俄罗斯套娃信封问题

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Solution354 {
    public int maxEnvelopes(int[][] envelopes) {
        Arrays.sort(envelopes, (o1, o2) -> {
            if (o1[0] == o2[0]) {
                return Integer.compare(o2[1], o1[1]);
            }
            return Integer.compare(o1[0], o2[0]);
        });

        // LIS
        List<Integer> a = new ArrayList<>();
        for (int[] e : envelopes) {
            int x = e[1];
            int j = searchInts(a, x);
            if (j == a.size()) a.add(x);
            else a.set(j, x);
        }
        return a.size();
    }

    private int searchInts(List<Integer> a, int key) {
        int l = 0, r = a.size();
        while (l < r) {
            int m = l + (r - l) / 2;
            if (a.get(m) >= key) r = m;
            else l = m + 1;
        }
        return l;
    }
}

1713. 得到子序列的最少操作次数

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Solution1713 {
    public int minOperations(int[] target, int[] arr) {
        int n = target.length;
        // 预处理下标
        Map<Integer, Integer> posMap = new HashMap<>();
        for (int i = 0; i < n; i++) {
            posMap.put(target[i], i);
        }

        List<Integer> a = new ArrayList<>();
        for (int ai : arr) {
            if (posMap.containsKey(ai)) {
                Integer x = posMap.get(ai);
                int j = searchInts(a, x);
                if (j == a.size()) a.add(x);
                else a.set(j, x);
            }
        }
        return n - a.size();
    }

    private int searchInts(List<Integer> a, int key) {
        int l = 0, r = a.size();
        while (l < r) {
            int m = l + (r - l) / 2;
            if (a.get(m) >= key) r = m;
            else l = m + 1;
        }
        return l;
    }
}

2111. 使数组 K 递增的最少操作次数

非递减,不要求严格递增。

import java.util.ArrayList;
import java.util.List;

public class Solution2111 {
    public int kIncreasing(int[] arr, int k) {
        int len = arr.length;
        int cnt = 0;
        for (int i = 0; i < k; i++) {
            List<Integer> list = new ArrayList<>();
            for (int j = i; j < len; j += k) {
                list.add(arr[j]);
            }
            cnt += lengthOfLIS(list);
        }
        return len - cnt;
    }

    public int lengthOfLIS(List<Integer> nums) {
        List<Integer> a = new ArrayList<>();
        for (int x : nums) {
            int j = searchInts(a, x);
            if (j == a.size()) a.add(x);
            else a.set(j, x);
        }
        return a.size();
    }

    private int searchInts(List<Integer> a, int key) {
        int l = 0, r = a.size();
        while (l < r) {
            int m = l + (r - l) / 2;
            if (a.get(m) > key) r = m;
            else l = m + 1;
        }
        return l;
    }
}































 





(全文完)