leetcode 801. 使序列递增的最小交换次数

96 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

1. 题目与解析

我们有两个长度相等且不为空的整型数组 nums1 和 nums2 。在一次操作中,我们可以交换 nums1[i] 和 nums2[i]的元素。

例如,如果 nums1 = [1,2,3,8] , nums2 =[5,6,7,4] ,你可以交换 i = 3 处的元素,得到 nums1 =[1,2,3,4] 和 nums2 =[5,6,7,8] 。 返回 使 nums1 和 nums2 严格递增 所需操作的最小次数 。

数组 arr 严格递增 且  arr[0] < arr[1] < arr[2] < ... < arr[arr.length - 1] 。

用例保证可以实现操作。  

输入: nums1 = [1,3,5,4], nums2 = [1,2,3,7]

输出: 1

解释: 交换 A[3] 和 B[3] 后,两个数组如下: A = [1, 3, 5, 7] , B = [1, 2, 3, 4] 两个数组均为严格递增的。 示例 2:

输入: nums1 = [0,3,5,8,9], nums2 = [2,1,4,6,9]

输出: 1

看到题目大家应该都会浮现出dp的想法,但是可能简单思考之后,发现状态转移函数非常复杂,也就放弃了,这里,我们可以一起思考dp状态转移函数的分析过程,以更好的梳理与推广解题思路。

  1. 首先,我们可以知道,对于每一位i,都只可能存在两种可能,交换了change或者是没有交换unchange
  2. 另外,我们需要保证,在i位,我们不管是交换没交换,都需要保证截止到这一位满足序列递增,只有这样才能进行从ii+1以至于所有位的推广。
  3. 因此我们分析change[i]以及unchange[i]可以如何从第i-1位转移过来。
  4. 我们现非别考虑如何从change[i-1]以及unchange[i-1]转移到change[i]以及unchange[i]
  5. 考虑从change[i-1]转移到change[i]
    • 首先必须保证nums1[i - 1] < nums1[i] && nums2[i - 1] < nums2[i],否则不满足递增的条件
    • 在上述条件的前提下,change[i] = change[i-1] + 1
  6. 考虑从unchange[i-1]转移到change[i]
    • 首先必须保证nums1[i - 1] < nums2[i] && nums2[i - 1] < nums1[i],否则不满足递增的条件
    • 在上述条件的前提下,change[i] = unchange[i-1] + 1
  7. 考虑从change[i-1]转移到unchange[i]
    • 首先必须保证nums1[i - 1] < nums2[i] && nums2[i - 1] < nums1[i],否则不满足递增的条件
    • 在上述条件的前提下,unchange[i] = change[i-1]
  8. 考虑从unchange[i-1]转移到unchange[i]
    • 首先必须保证nums1[i - 1] < nums1[i] && nums2[i - 1] < nums2[i],否则不满足递增的条件
    • 在上述条件的前提下,unchange[i] = unchange[i-1]
  9. 上述转移过程涉及到两个条件:
    • nums1[i - 1] < nums1[i] && nums2[i - 1] < nums2[i]
    • nums1[i - 1] < nums2[i] && nums2[i - 1] < nums1[i]
    • 针对这两个条件进行合并同类项就可以得到最后的状态转移方程

2. 题解

具体的题解如下所示:

class Solution {
    public int minSwap(int[] nums1, int[] nums2) {
        int ans = 0, change = 0, unchange = 0;
        for (int i = 1; i < nums1.length; i++) {
            int tmpChange = change, tmpUnchange = unchange;
            boolean flg1 = nums1[i - 1] < nums1[i] && nums2[i - 1] < nums2[i];
            boolean flg2 = nums1[i - 1] < nums2[i] && nums2[i - 1] < nums1[i];
            if (flg1 && flg2) {
                tmpChange = Math.min(unchange, change) + 1;
                tmpUnchange = Math.min(unchange, change);
            } else if (flg1 && !flg2) {
                tmpChange = Math.max(change, 1) + 1;
                tmpUnchange = unchange;
            } else if (!flg1 && flg2) {
                tmpChange = unchange + 1;
                tmpUnchange = Math.max(change, 1);
            }
            change = tmpChange;
            unchange = tmpUnchange;
        }
        return Math.min(change, unchange);
    }
}