【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]+1dp[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);
    }
};

你可能感兴趣的:(leetcode,算法,职场和发展)