leetcode
leetcode 701 ~ 750
使序列递增的最小交换次数

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

难度:

标签:

题目描述

代码结果

运行时间: 87 ms, 内存: 30.6 MB


/*
 * Problem: We have two equal-length integer arrays nums1 and nums2 that are not empty. In one operation, we can swap nums1[i] and nums2[i].
 * Goal: Return the minimum number of operations needed to make both nums1 and nums2 strictly increasing.
 * Explanation: Two arrays arr are strictly increasing if arr[0] < arr[1] < arr[2] < ... < arr[arr.length - 1].
 * Constraints: It is guaranteed that it is possible to achieve the goal.
 */

import java.util.stream.IntStream;

public class Solution {
    public int minSwap(int[] nums1, int[] nums2) {
        int n = nums1.length;
        int[] keep = new int[n];  // Minimum swaps to make arrays increasing if we don't swap at i
        int[] swap = new int[n];  // Minimum swaps to make arrays increasing if we swap at i
        keep[0] = 0;
        swap[0] = 1;

        IntStream.range(1, n).forEach(i -> {
            keep[i] = swap[i] = n;  // Initialize with a large number

            // Condition if current elements are already in increasing order without swapping
            if (nums1[i] > nums1[i - 1] && nums2[i] > nums2[i - 1]) {
                keep[i] = keep[i - 1];
                swap[i] = swap[i - 1] + 1;
            }

            // Condition if current elements will be in increasing order if swapped
            if (nums1[i] > nums2[i - 1] && nums2[i] > nums1[i - 1]) {
                keep[i] = Math.min(keep[i], swap[i - 1]);
                swap[i] = Math.min(swap[i], keep[i - 1] + 1);
            }
        });

        return Math.min(keep[n - 1], swap[n - 1]);
    }
}

解释

方法:

这个题解使用了动态规划的思想。定义了两个变量a和b,分别表示当前位置i不交换和交换时的最小交换次数。然后从第二个位置开始遍历数组,对于每个位置,根据前一个位置的状态和当前位置的大小关系,更新a和b的值。最后返回a和b中的较小值即为最小交换次数。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在动态规划中,`a`和`b`变量的初始值为什么分别设置为0和1,这样的设置有什么特别的意义吗?
在动态规划的这个问题中,`a`和`b`分别代表不进行交换和进行交换的最小交换次数。初始时,`a`被设置为0,因为在第一个元素位置我们假定没有进行任何交换,因此交换次数为0。而`b`设置为1表示第一个元素我们选择进行了交换,因此初始交换次数为1。这种设置是为了在动态规划过程中正确地追踪和计算不同位置上的交换情况和所需的最小交换次数。
🦆
在代码中,为什么当`nums1[i - 1] >= nums1[i]`或`nums2[i - 1] >= nums2[i]`时,选择将`a`和`b`的值设置为`y`和`x + 1`?这样的逻辑是基于什么考虑?
当`nums1[i - 1] >= nums1[i]`或`nums2[i - 1] >= nums2[i]`出现时,这意味着数组的这一部分不满足严格递增的条件,因此需要进行操作以保持递增序列。设置`a`为`y`(即前一个位置的`b`值)表示如果前一个位置进行了交换,当前位置不交换也能保持递增。将`b`设置为`x + 1`(即前一个位置的`a`值加1)表示如果前一个位置没有交换,当前位置必须交换来维持递增。这种设置确保了无论如何都能通过适当的交换来维持整个数组的严格递增顺序。
🦆
题解中提到当`nums1[i - 1] < nums2[i]`和`nums2[i - 1] < nums1[i]`时,可以选择交换或不交换,这种情况下的决策影响如何体现在代码中?
当`nums1[i - 1] < nums2[i]`和`nums2[i - 1] < nums1[i]`,即两种交叉的大小关系都满足时,表示无论是交换还是不交换,都可以维持严格递增的条件。在代码中,这种情况通过更新`a`和`b`来体现:`a = min(a, y)`和`b = min(b, x + 1)`。这里的`min`函数确保无论是选择交换还是不交换,都能取得当前位置可能的最小交换次数。这种灵活的选择使得整体的交换次数尽可能地小。
🦆
为什么在循环的每一步中,都需要重新计算`a`和`b`,而不能直接从前一个位置的结果推断出当前位置的最优解?
在动态规划中,每个位置的决策可能依赖于前一个位置的状态(交换或不交换),并且每个位置都可能面临不同的选择条件(如数组元素的大小关系)。因此,我们不能简单地从前一个位置的结果直接推断出当前位置的最优解,而需要基于当前的具体情况重新计算`a`和`b`。这种重新计算确保了每一步都是基于当前最全面信息的最优决策,从而得到全局的最小交换次数。

相关问题