解题思路:使用两个状态量来存储信息:
swap[i]表示交换A和B中第i个数字,A和B中前i个数字达到严格递增所需要的最小交换次数。
keep[i]表示不交换A和B中第i个数字,A和B中前i个数字达到严格递增所需要的最小交换次数。
对于A和B中的第i个数字,要考虑两种情况。
第一种情况是A[i]>A[i-1] && B[i]>B[i-1],同时有A[i]>B[i-1] && B[i]>A[i-1],这时候对于swap[i]和keep[i]的状态转移方程如下:
if(a[i]>a[i-1] && b[i]>b[i-1])
{
if(a[i]>b[i-1] && b[i]>a[i-1])
{
swap[i] = min(swap[i-1],keep[i-1]) + 1;
keep[i] = swap[i] - 1;
}
}
在符合上面两个条件的情况下,如果要交换A和B中的第i个数字,则可以找min(swap[i-1],keep[i-1])+1,因为不管是交换第i-1个数字还是保持第i-1数字,对于是否交换第i个数字都没有影响,因为都符合条件,因此我们选择swap[i-1]和keep[i-1]中较小的那个值,然后加1。这样就得到了在符合条件下的交换第i个数字所需要的最小交换次数。
同理,对于keep[i],因为不管是交换第i-1个数字得到的swap[i-1]还是不交换第i-1个数字得到的keep[i-1],都对keep[i]没啥影响,因此我们选择swap[i-1]和keep[i-1]中较小的那个,并赋值给keep[i]。也可以表示为keep[i] = swap[i] - 1。具体的形式就和上面的代码一下。
要是符合条件A[i]>A[i-1] && B[i]>B[i-1],但是不符合条件A[i]>B[i-1] && B[i]>A[i-1]时,我们需要考虑另外的情况,具体的C++代码如下:
if(a[i]>a[i-1] && b[i]>b[i-1])
{
if(a[i]>b[i-1] && b[i]>a[i-1]) //两种情况都符合
{
swap[i] = min(swap[i-1],keep[i-1]) + 1;
keep[i] = swap[i] - 1;
}
else //不符合a[i]>b[i-1] && b[i]>a[i-1]
{
swap[i] = swap[i-1] + 1;
keep[i] = keep[i-1];
}
}
在符合a[i]>a[i-1] && b[i]>b[i-1]条件,但是不符合a[i]>b[i-1] && b[i]>a[i-1]条件时,要找swap[i]的状态转移方程,可以分析一下,因为不符合a[i]>b[i-1] && b[i]>a[i-1],如果我们交换了第i个数字,那么前i个数字必定不符合严格递增关系。如果要变成符合严格递增关系的子集,则要将前i-1个数组进行变换。很幸运,swap[i-1]表示的是交换第i-1个数字得到严格递增关系的数组所需的最小交换次数。那么就可以得到swap[i] = swap[i-1] + 1。
同理,对于keep[i],因为第i个数字不符合a[i]>b[i-1] && b[i]>a[i-1],要求第i个数字保持不变得到前i个数组严格递增所需的最小交换次数,则分析前i-1个数组中的swap[i-1]和keep[i-1]。可以得知keep[i] = keep[i-1] + 1。意思是要求第i个数字不变的最小交换次数,则可以在第i-1个数字不变得到递增数组所需的最小交换次数上加1。注意不能用到swap[i-1],因为swap[i-1]是交换了第i-1个数字的。当交换第i-1个数字时,如果第i个数字不交换,是没办法得到严格递增数组的。
第二种情况是A[i]<A[i-1] || B[i]<B[i-1],这种情况下考虑swap[i]和keep[i]的状态转移方程,根据上面的分析,我们可以简单地得到:
swap[i] = keep[i-1]+1;
keep[i] = swap[i-1];
这两个状态转移方程的意思是,如果交换第i个数字,则是在第i-1个数字不交换得到递增数组的最小交换次数的程度上+1。同理,如果不交换第i个数字,则因为违反了严格递增关系,需要把前i-1个数组进行变换,那么恰好swap[i-1]的意思就是交换第i-1个数字得到严格递增数组所需的最小交换次数,那么就可以得到keep[i] = swap[i-1];
综上分析,可以得到整体C++代码如下:
class Solution {
public:
int minSwap(vector<int>& a, vector<int>& b) {
int length = a.size();
vector<int> swap(length,1); //用于存储交换第i个数字,使前i个数字达到严格递增数组所需的最小交换次数
vector<int> keep(length,0); //用于存储不交换第i个数字,使前i个数字达到严格递增数组所需的最小交换次数
for(int i=1;i<length;i++)
{
if(a[i]>a[i-1] && b[i]>b[i-1]) //如果A(B)中第i个数字和A(B)中第i-1个数字符合严格递增关系
{
if(a[i]>b[i-1] && b[i]>a[i-1]) //如果A(B)中第i个数字和B(A)中第i-1个数字符合严格递增关系
{
swap[i] = min(swap[i-1],keep[i-1]) + 1;
keep[i] = swap[i] - 1;
}
else //如果A(B)中第i个数字和B(A)中第i-1个数字不符合严格递增关系
{
swap[i] = swap[i-1] + 1;
keep[i] = keep[i-1];
}
}
else //如果A(B)中第i个数字和A(B)中第i-1个数字不符合严格递增关系
{
swap[i] = keep[i-1] + 1;
keep[i] = swap[i-1];
}
}
return min(swap[length-1],keep[length-1]); //返回交换或者不交换两者之间的较小的值
}
};
这里解题的关键是要理解swap[i]和keep[i]代表的意义,并理解swap[i-1]、swap[i]、keep[i-1]、keep[i]之间的关系。