持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
题目描述
我们有两个长度相等且不为空的整型数组 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] 。
注意:
用例保证可以实现操作。
示例 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
提示:
2 <= nums1.length <= 105
nums2.length == nums1.length
0 <= nums1[i], nums2[i] <= 2 * 105
解题思路
首先看着数据的长度,想法为n平方复杂度的直接打住,根据题意,要找出使nums1和nums2都递增,同时交换数组下标i的最少次数,因为说用例保证可以实现操作,并且只能交换两个数组的同一个位置,所以只可能有两种情况:
- nums1[i] > nums1[i - 1] && nums2[i] > nums2[i - 1]
- nums1[i] > nums2[i - 1] && nums2[i] > nums1[i - 1]
或者说这两种情况都满足。 这样我们可以用dp来记录前一种的情况,因为一个位置的数要么交换要么不交换,所以我们可以让dp[i][0]表述i处数据不交换的最少次数,dp[i][1]表示i处数据交换的最少次数。
当满足第一种情况时,如果i处不交换,那么dp[i][0]交换的最少次数就和上一次的一样,也就是dp[i-1][0];如果i处交换,那么它的上一次也需要交换才满足递增,所以为dp[i-1][1]+1,+1表示这次的交换。当满足第二种情况时,如果i处不交换,那么它的上一次必须要交换,即dp[i-1][1];如果i处交换,上次就没有交换,就为dp[i-1][0]+1。 当两种情况都满足时,取它们次数的最小值。最开始是dp[0][0]=0,不交换;dp[0][1]=1,交换了一次。
代码
class Solution {
public int minSwap(int[] nums1, int[] nums2) {
int n = nums1.length;
int a = 0, b = 1;
for (int i = 1; i < n; i++) {
int aTemp = a, bTemp = b;
a = b = n;
// 当前对应的都大于
if (nums1[i] > nums1[i - 1] && nums2[i] > nums2[i - 1]){
a = Math.min(a,aTemp); // 当前不交换,次数与前一个不交换次数相同
b = Math.min(b,bTemp + 1); // 当前交换,那么上一次也要交换,次数+1
}
// 当前交叉大于
if (nums1[i] > nums2[i - 1] && nums2[i] > nums1[i - 1]){
a = Math.min(a,bTemp); // 当前不交换,次数为上次交换次数相同
b = Math.min(b,aTemp + 1); // 当前交换,上次不交换+1
}
// 以上两个条件至少有一个会满足,如果都满足那么久会选择其中交换次数较小的那个
}
return Math.min(a,b);
}
}
总结
本题的难点在于想到只有两种情况,然后用动态规划来运用上一次的值来更新本次的值。