返回

动态规划状态机DP:801. 使序列递增的最小交换次数

后端

题目背景

给你一个整数数组 nums,你需要选出一个最短的子序列,使得剩下元素排列后严格递增。

对于长度为 n 的数组 nums,选出一个最短的子序列,剩余元素排列后严格递增,共有 2^n 种选择,复杂度太高。

我们将子序列划分为连续的连续块。具体来说,如果存在一些 i ,使得 0 <= i < nnums[0] < nums[1] < ... < nums[i],则 nums[0], nums[1], ..., nums[i] 是一个递增的连续块。

动态规划状态机方法的时间复杂度可以降低到 O(n log n)

解决思路

  1. 确定状态:

定义子问题为:对于数组 nums 的前 i 个元素,要使得子序列递增,最少需要删除多少个元素?我们记这个最少删除数为 dp[i]

  1. 状态转移方程:

子问题 dp[i] 可以由子问题 dp[j] 得出,其中 j < i,并且 nums[j] < nums[i]。我们可以通过比较 dp[i]dp[j] + 1 来得到子问题 dp[i] 的最优解。

  1. 初始化:

我们可以将 dp[0] 初始化为 0,因为对于长度为 0 的数组,不需要删除任何元素。

  1. 计算:

我们可以从 i = 1 开始,按照顺序计算 dp[i]。对于每一个 i,我们可以从 j = 0 开始,遍历所有 j < inums[j] < nums[i] 的元素。如果 dp[j] + 1 < dp[i] ,那么我们就更新 dp[i] 的值为 dp[j] + 1

  1. 结果:

在计算完所有子问题后,我们可以返回 dp[n - 1] 的值,它表示整个数组 nums 的最少删除数。

代码实现

import java.util.Arrays;

public class Solution {

    public int minSwaps(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    dp[i] = Math.min(dp[i], dp[j] + 1);
                }
            }
        }
        int minSwaps = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            minSwaps = Math.min(minSwaps, dp[i]);
        }
        return minSwaps;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        int[] nums = {1, 3, 5, 2, 4, 6, 7, 8, 9};
        int minSwaps = solution.minSwaps(nums);
        System.out.println(minSwaps); // 1
    }
}

总结

这篇文章讨论了一道困难的LeetCode题目,该题涉及动态规划的状态机DP解法。该题难度较大,标签为动态规划和多状态。本文将以Java语言为基础进行展示。