1题目理解
输入:两个int数组A和B,长度都不为0,并且长度相同。
输出:最小交换次数。
规则:最终想要得到两个严格递增的数组。如果原始数组不符合要求,可以在相同的位置交换A、B数组元素。也就是说可以交换A[i]和B[i],使得数组严格递增。并且题目可以保证输入的数组是有效的数组。
例子:
Input: A = [1,3,5,4], B = [1,2,3,7]
Output: 1
Explanation:
交换 A[3] and B[3]得到的序列是:
A = [1, 3, 5, 7] and B = [1, 2, 3, 4]
它们都是严格递增的.
2 暴力搜索
这道题目一眼是看不出递归方程的,所以只能从暴力搜索开始。
我们每次比较第i位元素:如果 A[i]<=A[i-1] 或者 B[i]<=B[i-1] ,那这个时候不符合条件,是一定要交换A[i]和B[i]的。其他情况下,A[i]和B[i]可以交换也可以不交换。当i=0的时候,A[i]和B[i]也是可以交换也可以不交换。
一直比较到数组长度的时候,记录最小交换次数。
因为每个位置都有2种选择,所以时间复杂度是
O
(
n
2
)
O(n^2)
O(n2)。
class Solution {
private int result;
public int minSwap(int[] A, int[] B) {
result = A.length;
minSwap(A,B,0,0);
return result;
}
private void minSwap(int[] A ,int[] B,int index,int swapCount){
if(index >= A.length){
result = Math.min(result,swapCount);
}else{
if(index >0 && (A[index]<=A[index-1] || B[index]<=B[index-1])){
//必须换
swap(A,B,index);
if(A[index]<=A[index-1] || B[index]<=B[index-1]){
swap(A,B,index);
return;
}
minSwap(A,B,index+1,swapCount+1);
swap(A,B,index);
}else{
minSwap(A,B,index+1,swapCount);
swap(A,B,index);
if(index>0 && (A[index]<=A[index-1] || B[index]<=B[index-1])){
swap(A,B,index);
return;
}
minSwap(A,B,index+1,swapCount+1);
swap(A,B,index);
}
}
}
private void swap(int[] A,int[]B,int index){
int t = A[index];
A[index] = B[index];
B[index] = t;
}
}
当这样写完代码之后提交肯定超时。但是根据这个却不知道怎么写递归方程。
3 动态规划
既然根据暴力找不到方程,那就再分析。严格递增是A[i]>A[i-1],所以在考虑第i步的最小交换次数的时候,只需要考虑第i-1步的最小交换次数以及大小关系。
我们令keep[i]表示从0到i是严格递增序列需要交换的最少次数,并且A[i]和B[i]不交换。令swap[i]表示从0到i是严格递增序列需要交换的最少次数,并且A[i]和B[i]交换。
在例子中
1 3 5
1 2 3
3.1第一种情况
当i=2的时候,A[i]>A[i-1] 并且B[i]>B[i-1],在这种状态下A[i]、B[i]可以交换也可以不交换。
如果A[i]、B[i]不交换,那A[i-1]、B[i-1]也应该不换。如果一换的话可能就不是严格递增子序列了。例如3和2换了,5和3不换,那序列变为1 2 5和 1 3 3。这样是不符合要求的。所以keep[i]=keep[i-1],
如果A[i]、B[i]交换,那A[i-1]、B[i-1]也应该交换。例如5和3换了,3和2不换,那序列变为1 3 3和1 2 5。不符合要求。所以swap[i] = swap[i-1]+1。
3.2第二种情况
我们再考虑A[i]和B[i-1]的关系。如果A[i]>B[i-1]并且B[i]>B[i-1]。
在例子中
1 3 5 4
1 2 3 7
在当i=3的时候,就符合这种情形。我们同样考虑A[i]、B[i]交换,不交换两种情况。
如果A[i]、B[i]不交换,那么A[i-1]、B[i-1]应该交换。如果不交换是可能不符合要求的。例子中5和3不交换,4和7也不交换,那结果不符合要求。所以keep[i] = swap[i-1]。
如果A[i]、B[i]交换,那A[i-1]、B[i-1]应该不交换。同样换一下,不符合要求(1 3 3 7,1 2 5 4)我们只比较最后两位。所以swap[i] = keep[i] + 1。
接着考虑A[i]>A[i-1] 并且B[i]>B[i-1] 和 A[i]>B[i-1]并且B[i]>A[i-1]应该是可能同时出现。所以在考虑第二种情况下的计算式的时候,需要改变一下。keep[i] = min(keep[i],swap[i-1]) , swap[i] = min(swap[i],keep[i] + 1)。
题目思路来源于花花酱
开始写代码吧。
class Solution {
private int result;
public int minSwap(int[] A, int[] B) {
int n = A.length;
int[] swap = new int[n];
int[] keep = new int[n];
swap[0] = 1;
for(int i = 1;i<n;i++){
swap[i] = n;
keep[i] = n;
if(A[i] > A[i-1] && B[i] > B[i-1]){
keep[i] = keep[i-1];
swap[i] = swap[i-1] + 1;
}
if(A[i]>B[i-1] && B[i]>A[i-1]){
keep[i] = Math.min(keep[i],swap[i-1]);
swap[i] = Math.min(swap[i],keep[i-1]+1);
}
}
return Math.min(swap[n-1],keep[n-1]);
}
}
时间复杂度O(n)。空间复杂度可以优化为O(1)。