题目来源:https://leetcode.cn/problems/minimum-swaps-to-make-sequences-increasing/
大致题意:
给两个数组 nums1 和 nums2,一次交换操作可以交换相同索引处两个数组的元素,求最少需要交换多少次可以使两个数组都递增
如 [1, 5, 4, 8] 和 [2, 3, 6, 9],可以交换索引 2 处元素,使两个数组变为 [1, 5, 6, 8] 和 [2, 3, 4, 9],这样只交换一次两个数组都满足递增
题目保证两个数组能在交换一定次数后都递增
思路
首先分析两个数组当前位置元素与上一个位置元素的关系,有以下几种
- nums1[i] > nums1[i - 1] 且 nums2[i] > nums2[i - 1],这种情况不需要交换即满足递增。如果上一位交换了,那么当前位也需要交换
- nums1[i] > nums1[i - 1] 且 nums2[i] > nums2[i - 1],这种情况需要交换当前位才满足递增,如果上一位交换了,那么当前位不需要交换
- nums1[i] > nums1[i - 1] 且 nums2[i] > nums2[i - 1],同时 nums1[i] > nums1[i - 1],nums2[i] > nums2[i - 1],这种情况不管上一位交换与否都满足递增
于是可以使用两个标志位 unChange 和 change 表示上一位不交换和交换满足递增所需的最小次数
那么对于上述三种情况(第三种情况包含在前两种的判断中),unChange 和 change 的更新方法为
- 使用 unChangeTemp 和 changeTemp,表示本轮操作后不交换和交换满足递增所需的最小次数,初始设置为最大值 n
- 首先判断如果满足第一个条件,那么 unChangeTemp 即为上一轮不交换的次数,changeTemp 更新为上一轮交换次数 + 1
- 之后判断如果满足第二个条件,那么 unChangeTemp 为当前值与上一轮交换次数的最小值(因为当前值可能在上一个判断中更新,即考虑第三个条件,两种情况都满足时的判断),changeTemp 更新为上一轮不交换次数 + 1 与当前值的最小值 (因为当前值可能在上一个判断中更新,即考虑第三个条件,两种情况都满足时的判断)
- 然后根据 unChangeTemp 和 changeTemp 更新标志位 unChange 和 change
最终返回标志位 unChange 和 change 的最小值即可
具体看代码:
class Solution {
public int minSwap(int[] nums1, int[] nums2) {
int n = nums1.length;
int unChange = 0;
int change = 1; // 初始时,交换首位元素,操作次数为 1
for (int i = 1; i < n; i++) {
// 初始化当前位递增的最小交换次数
int unChangeTemp = n;
int changeTemp = n;
// 如果不交换就满足递增
if (nums1[i] > nums1[i - 1] && nums2[i] > nums2[i - 1]) {
// 当前位不交换就满足递增
// 当前位不交换的操作次数与上一轮相同
unChangeTemp = unChange;
// 上一位交换了,当前位交换才能满足递增,操作次数为上一轮交换次数 + 1
changeTemp = change + 1;
}
// 如果交换后才满足递增
if (nums1[i] > nums2[i - 1] && nums2[i] > nums1[i - 1]) {
// 当前位必须交换,或者上一位交换才满足递增
// 当前位不交换,上一位交换
unChangeTemp = Math.min(unChangeTemp, change);
// 当前位交换,上一位不交换
changeTemp = Math.min(unChange + 1, changeTemp);
}
change = changeTemp;
unChange = unChangeTemp;
}
return Math.min(change, unChange);
}
}