【DP】个人练习-Leetcode-801. Minimum Swaps To Make Sequences Increasing
题目链接:https://leetcode.cn/problems/minimum-swaps-to-make-sequences-increasing/
题目大意:给出两个数列nums1[], nums2[]
,两个数列长度相同。可以操作一次:交换某个位置i
上的两个数列的元素。求使得两个数列变为严格递增的最少操作次数。
思路:又是DP,还是hard,寄了。原本的思路是,某个位置只能换或者不换,那么用决策树来整,但发现每个节点都要保存之前的状态,似乎开销太大了…
看了题解,用二维DP做。其实最关键的地方是【题目保证一定能通过操作使得两个数列变为严格递增】,也就是说,类似于
1 2
8 8
这样的数列是不会出现的,因为它无法通过操作使得两个数列都严格递增。
而题解从中提取了关键信息,这两个数组必然有以下至少一种情况:
nums1[i] > nums1[i-1] && nums2[i] > nums2[i-1]
nums1[i] > nums2[i-1] && nums2[i] > nums1[i-1]
否则【交换】或者【不交换】都无法使得两个数组严格递增
用dp[i][j]
表示在下标[0, i]
范围内,如果i
位置交换(j == 1
)或者不交换(j == 0
)是的这个范围的数组严格递增的最小操作次数。那么转移关系有
- 若为第一种情况,那么可以选择
i-1, i
这两个位置【都交换】或者【都不交换】表现为dp[i][1] = dp[i-1][1]+1
和dp[i][0] = dp[i-1][0]
- 若为第二种情况,那么可以选择【仅
i-1
交换】或者【仅i
交换】,表现为dp[i][0] = dp[i-1][1]
和dp[i][1] = dp[i-1][0]+1
- 如果两种情况都有,那么取小的
又因为转移仅发生在dp[i-1]
和dp[i]
之间,因此我们利用【滑动数组】,仅保存两个数即可从前往后转移完,得出答案。
完整代码
class Solution {
public:int minSwap(vector<int>& nums1, vector<int>& nums2) {int N = nums1.size();int dp0 = 0, dp1 = 1;for (int i = 1; i < N; i++) {int pre0 = dp0, pre1 = dp1;dp0 = dp1 = N+1;if (nums1[i] > nums1[i-1] && nums2[i] > nums2[i-1]) {dp0 = min(dp0, pre0);dp1 = min(dp1, pre1+1);}if (nums1[i] > nums2[i-1] && nums2[i] > nums1[i-1]) {dp0 = min(dp0, pre1);dp1 = min(dp1, pre0+1);}}return min(dp0, dp1);}
};