文章目录
- 1题目理解
- 2 暴力搜索
- 3 动态规划
- 3.1第一种情况
- 3.2第二种情况
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(n2)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)。