We have two integer sequences A and B of the same non-zero length.

We are allowed to swap elements A[i] and B[i].  Note that both elements are in the same index position in their respective sequences.

At the end of some number of swaps, A and B are both strictly increasing.  (A sequence is strictly increasing if and only if A[0] < A[1] < A[2] < ... < A[A.length - 1].)

Given A and B, return the minimum number of swaps to make both sequences strictly increasing.  It is guaranteed that the given input always makes it possible.

Example:
Input: A = [1,3,5,4], B = [1,2,3,7]
Output: 1
Explanation:
Swap A[3] and B[3]. Then the sequences are:
A = [1, 3, 5, 7] and B = [1, 2, 3, 4]
which are both strictly increasing.

Note:

  • A, B are arrays with the same length, and that length will be in the range [1, 1000].
  • A[i], B[i] are integer values in the range [0, 2000].

这道题给了我们两个长度相等的数组A和B,说是可以在任意位置i交换A[i]和B[i]的值,我们的目标是让数组A和B变成严格递增的数组,让我们求出最少需要交换的次数。博主最先尝试了贪婪算法,就是遍历数组,如果当前数字小于等于前面一个数字,那么就交换一下,但是问题就来了,到底是交换当前位置的数字,还是前一个位置的数字呢,比如下面这个例子:

0   4   4   5

0   1   6   8

我们到底是交换4和1呢,还是4和6呢,虽然两种方法都能让前三个数字严格递增,但是如果交换了4和6,那么第一个数组的最后一个5就又得交换了,那么就要多交换一次,所以这个例子是交换4和1,但是对于下面这个例子:

0   4   4   7

0   1   6   5

那么此时我们就要交换4和6了,这样只要交换一次就能使两个数组都变成严格递增的数组了。所以这道题用贪婪算法不work,我们必须使用别的方法,那么此时动态规划Dynamic Programming就闪亮登场了。

像这种求极值的题目,不是Greedy就是DP啊,一般难题偏DP的比较多。而DP解法的第一步就是要确定dp数组该怎么定义,如果我们定义一个一维数组dp,其中dp[i]表示使得范围[0, i]的子数组同时严格递增的最小交换次数,这样的话状态转移方程就会十分的难写,因为我们没有解耦合其内在的关联。当前位置i是否交换,只取决于和前面一位是否是严格递增的,而前一位也有交换或者不交换两种状态,那么前一位的不同状态也会影响到当前是否交换,这跟之前那道Best Time to Buy and Sell Stock with Transaction Fee就十分到类似了,那道题的股票也有保留或者卖出两种状态不停的切换。那么这里我们也需要维护两种状态,swap和noSwap,那么swap[i]表示范围[0, i]的子数组同时严格递增且当前位置i需要交换的最小交换次数,noSwap[i]表示范围[0, i]的子数组同时严格递增且当前位置i不交换的最小交换次数,两个数组里的值都初始化为n。由于需要跟前一个数字比较,所以我们从第二个数字开始遍历,那么就需要给swap和noSwap数组的第一个数字提前赋值,swap[0]赋值为1,因为其表示i位置需要交换,noSwap[0]赋值为0,因为其表示i位置不需要交换。

好,下面来分析最难的部分,状态转移方程。由于这道题限制了一定能通过交换生成两个同时严格递增的数组,那么两个数组当前位置和前一个位置之间的关系只有两种,一种是不用交换,当前位置的数字已经分别大于前一个位置,另一种是需要交换后,当前位置的数字才能分别大于前一个数字。那么我们来分别分析一下,如果当前位置已经分别大于前一位置的数了,那么讲道理我们是不需要再进行交换的,但是swap[i]限定了我们必须要交换当前位置i,那么既然当前位置要交换,那么前一个位置i-1也要交换,同时交换才能继续保证同时递增,这样我们的swap[i]就可以赋值为swap[i-1] + 1了。而noSwap[i]直接赋值为noSwap[i-1]即可,因为不需要交换了。第二种情况是需要交换当前位置,才能保证递增。那么swap[i]正好也是要交换当前位置,而前一个位置不能交换,那么即可以用noSwap[i-1] + 1来更新swap[i],而noSwap[i]是不能交换当前位置,那么我们可以通过交换前一个位置来同样实现递增,即可以用swap[i-1]来更新noSwap[i],当循环结束后,我们在swap[n-1]和noSwap[n-1]中返回较小值即可,参见代码如下:

解法一:

class Solution {
public:
int minSwap(vector<int>& A, vector<int>& B) {
int n = A.size();
vector<int> swap(n, n), noSwap(n, n);
swap[] = ; noSwap[] = ;
for (int i = ; i < n; ++i) {
if (A[i] > A[i - ] && B[i] > B[i - ]) {
swap[i] = swap[i - ] + ;
noSwap[i] = noSwap[i - ];
}
if (A[i] > B[i - ] && B[i] > A[i - ]) {
swap[i] = min(swap[i], noSwap[i - ] + );
noSwap[i] = min(noSwap[i], swap[i - ]);
}
}
return min(swap[n - ], noSwap[n - ]);
}
};

我们可以优化上面解法的空间复杂度,由于当前位置的值只跟前一个位置相关,所以我们并不需要保存整个数组,用四个变量来分别表示当前位置和前一个位置的各两种状态,可以实现同样的效果,参见代码如下:

解法二:

class Solution {
public:
int minSwap(vector<int>& A, vector<int>& B) {
int n1 = , s1 = , n = A.size();
for (int i = ; i < n; ++i) {
int n2 = INT_MAX, s2 = INT_MAX;
if (A[i - ] < A[i] && B[i - ] < B[i]) {
n2 = min(n2, n1);
s2 = min(s2, s1 + );
}
if (A[i - ] < B[i] && B[i - ] < A[i]) {
n2 = min(n2, s1);
s2 = min(s2, n1 + );
}
n1 = n2;
s1 = s2;
}
return min(n1, s1);
}
};

类似题目:

Best Time to Buy and Sell Stock with Transaction Fee

参考资料:

https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/solution/

https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/discuss/119835/Java-O(n)-DP-Solution

https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/discuss/120516/C++-solution-with-explanation

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Minimum Swaps To Make Sequences Increasing 使得序列递增的最小交换的更多相关文章

  1. LeetCode 801. Minimum Swaps To Make Sequences Increasing

    原题链接在这里:https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/ 题目: We have two in ...

  2. 【LeetCode】801. Minimum Swaps To Make Sequences Increasing 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 动态规划 参考资料 日期 题目地址:https:// ...

  3. [Swift]LeetCode801. 使序列递增的最小交换次数 | Minimum Swaps To Make Sequences Increasing

    We have two integer sequences A and B of the same non-zero length. We are allowed to swap elements A ...

  4. 801. Minimum Swaps To Make Sequences Increasing

    We have two integer sequences A and B of the same non-zero length. We are allowed to swap elements A ...

  5. [LeetCode] 801. Minimum Swaps To Make Sequences Increasing 最少交换使得序列递增

    We have two integer sequences A and B of the same non-zero length. We are allowed to swap elements A ...

  6. 【leetcode】801. Minimum Swaps To Make Sequences Increasing

    题目如下: We have two integer sequences A and B of the same non-zero length. We are allowed to swap elem ...

  7. 801. Minimum Swaps To Make Sequences Increasing 为使两个数组严格递增,所需要的最小交换次数

    [抄题]: We have two integer sequences A and B of the same non-zero length. We are allowed to swap elem ...

  8. Java实现 LeetCode 801 使序列递增的最小交换次数 (DP)

    801. 使序列递增的最小交换次数 我们有两个长度相等且不为空的整型数组 A 和 B . 我们可以交换 A[i] 和 B[i] 的元素.注意这两个元素在各自的序列中应该处于相同的位置. 在交换过一些元 ...

  9. [LeetCode] Minimum Window Subsequence 最小窗口序列

    Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequence of ...

随机推荐

  1. Oracle使用PLSQL导入数据后中文乱码的解决方法

    新建环境变量 名:NLS_LANG 值:SIMPLIFIE DCHINESE_CHINA.ZHS16GBK 保存后重启PLSQL Developer 重新导入. 如果还是乱码,将上面8的环境变量值改为 ...

  2. java对象在内存中的结构

    在HotspotJVM中,32位机器下,Integer对象的大小是int的几倍? 我们都知道在java语言规范已经规定了int的大小是4个字节,那么Integer对象的大小是多少呢?要知道一个对象的大 ...

  3. 在centos7下安装.net core

    在这里记录下安装的过程: 一开始需要去官网下载centos相关的dotnetcore的sdk 上传到linux,解压,发现需要安装libunwind, 安装libunwind:yum install  ...

  4. 移动端bug集合

    移动端软键盘遮挡输入框&IOS移动端点击输入框字体放大&IOS点击闪烁 移动端软键盘遮挡输入框  ——>  转载自: https://www.jb51.net/article/1 ...

  5. python3 字典常见用法总结

    python3 字典常见用法总结 Python字典是另一种可变容器模型,且可存储任意类型对象,如字符串.数字.元组等其他容器模型. 一.创建字典 字典由键和对应值成对组成.字典也被称作关联数组或哈希表 ...

  6. 在c:forEach与s:iterator里面使用if标签判断当前位置是否为2的倍数

    在c:forEach与s:iterator里面使用if标签判断当前位置是否为2的倍数 c:forEach: <c:forEach var="workflow" items=& ...

  7. html(jQuery)替换字符串(全部替换)

    var  str= "a<br/>b<br/>c<br/>"; var Newstr = str.replace("<br/&g ...

  8. IISARR方式整合Tomcat失敗

    需要在IIS安裝ARR 目标服务器:targetServer 配置反向代理的服务器:reveseProxServer 1.确定最终访问的网址:比如www.baidu.com  .www.csdn.ne ...

  9. 论文阅读笔记四十二:Going deeper with convolutions (Inception V1 CVPR2014 )

    论文原址:https://arxiv.org/pdf/1409.4842.pdf 代码连接:https://github.com/titu1994/Inception-v4(包含v1,v2,v4)   ...

  10. 一步步建立 Vue + Cesium 初始化项目

    一步步建立 Vue + Cesium 初始化项目 初始化 Vue 项目 升级 npm npm install -g npm 安装 @vue/cli 和 @vue/cli-service-global ...