动态规划状态机DP:801. 使序列递增的最小交换次数
2023-12-12 21:41:13
题目背景
给你一个整数数组 nums
,你需要选出一个最短的子序列,使得剩下元素排列后严格递增。
对于长度为 n
的数组 nums
,选出一个最短的子序列,剩余元素排列后严格递增,共有 2^n
种选择,复杂度太高。
我们将子序列划分为连续的连续块。具体来说,如果存在一些 i ,使得 0 <= i < n
且 nums[0] < nums[1] < ... < nums[i]
,则 nums[0], nums[1], ..., nums[i]
是一个递增的连续块。
动态规划状态机方法的时间复杂度可以降低到 O(n log n)
。
解决思路
- 确定状态:
定义子问题为:对于数组 nums
的前 i
个元素,要使得子序列递增,最少需要删除多少个元素?我们记这个最少删除数为 dp[i]
。
- 状态转移方程:
子问题 dp[i]
可以由子问题 dp[j]
得出,其中 j < i
,并且 nums[j] < nums[i]
。我们可以通过比较 dp[i]
和 dp[j] + 1
来得到子问题 dp[i]
的最优解。
- 初始化:
我们可以将 dp[0]
初始化为 0,因为对于长度为 0 的数组,不需要删除任何元素。
- 计算:
我们可以从 i = 1
开始,按照顺序计算 dp[i]
。对于每一个 i
,我们可以从 j = 0
开始,遍历所有 j < i
且 nums[j] < nums[i]
的元素。如果 dp[j] + 1 < dp[i]
,那么我们就更新 dp[i]
的值为 dp[j] + 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语言为基础进行展示。