【动态规划】801. 使序列递增的最小交换次数(每日一题)

回顾题目

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-swaps-to-make-sequences-increasing

我们有两个长度相等且不为空的整型数组 nums1 和 nums2 。在一次操作中,我们可以交换 nums1[i] 和 nums2[i]的元素。

例如,如果 nums1 = [1,2,3,8] , nums2 =[5,6,7,4] ,你可以交换 i = 3 处的元素,得到 nums1 =[1,2,3,4] 和 nums2 =[5,6,7,8] 。
返回 使 nums1 和 nums2 严格递增 所需操作的最小次数

数组 arr 严格递增 且 arr[0] < arr[1] < arr[2] < … < arr[arr.length - 1] 。

注意:用例保证可以实现操作。

示例 1:

输入: nums1 = [1,3,5,4], nums2 = [1,2,3,7]
输出: 1

解释:
交换 A[3] 和 B[3] 后,两个数组如下:
A = [1, 3, 5, 7] , B = [1, 2, 3, 4]
两个数组均为严格递增的。

示例 2:

输入: nums1 = [0,3,5,8,9], nums2 = [2,1,4,6,9]
输出: 1

提示:

2 <= nums1.length <= 105
nums2.length == nums1.length
0 <= nums1[i], nums2[i] <= 2 * 105
思路分析:

第一眼看这个题目,首先会想到比较nums1和nums2各自第i个元素和其前后元素的大小关系,从而进一步分析:

  1. 题目里明确提出“用例保证可以实现操作。”,说明在每次只交换两个数组同一位置的元素情况下,两个数组一定有严格递增的解。即在交互n次以后,一定能够保证每个元素都满足
 nums1[i]>nums1[i-1]&&nums2[i]>nums2[i-1]
  1. 因此可以将情况聚焦在nums[i]和nums[i-1]上分析,只有这几种情况:

(1) 两个数组元素都满足严格递增 且 元素互换数组后也满足严格递增

 nums1[i]>nums1[i-1]  
 nums2[i]>nums2[i-1]
 nums1[i]>nums2[i-1]
 nums2[i]>nums1[i-1]
 例:
 nums1=[3,5];
 nums2=[4,7];

(2)两个数组元素都满足严格递增 但 元素互换数组后不满足严格递增

 nums1[i]>nums1[i-1]  
 nums2[i]>nums2[i-1]
 nums1[i]<=nums2[i-1]
 nums2[i]<=nums1[i-1]
 例:
 nums1=[4,5];
 nums2=[3,4];

(3)两个数组元素不满足严格递增 但 元素互换数组后满足严格递增

 nums1[i]<=nums1[i-1]  
 nums2[i]<=nums2[i-1]
 nums1[i]>nums2[i-1]
 nums2[i]>nums1[i-1]
 例:
 nums1=[6,5];
 nums2=[4,7];

因为题目保证一定有解,所有不可能出现的情况是:
两个元素不满足严格递增 且 元素互换数组后也不递增

 nums1[i]<=nums1[i-1]  
 nums2[i]<=nums2[i-1]
 nums1[i]<=nums2[i-1]
 nums2[i]<=nums1[i-1]
 例:
 nums1=[3,2];
 nums2=[4,7];
  1. 在分析完两个元素可能的情况之后,发现题目最后要求操作的最小次数,但操作次数的增减取决于每一个元素的交换情况(交换or未交换),于是可以考虑设置动态数组 dp[ i ] [ j ] 表示当前元素交换状态的最小操作次数, i 表示当前元素的索引值,j 表示当前元素的交换状态(交换为1,不交换为0)。从i=0开始分析,第一个元素因为没有前导元素比较,因此可交换也可以不交换,从而有dp[0][0]=0(不交换),dp[0][1]=1(交换,次数加1),根据上面分析的情况进行分类,最后返回dp[n-1][0]和dp[n-1][1]的最小值即可。(n为数组长度)
题解代码+注释
class Solution {
public:
    int minSwap(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size();
        vector<vector<int>>dp(n,vector<int>(2));//创建动态数组dp[i][j]
        //初始状态交换与不交换的最小次数
        dp[0][0]=0;//不交换 
        dp[0][1]=1;//交换
        for(int i=1;i<n;++i){
        	//第(1)种情况:
            if(nums1[i]>nums1[i-1]&&nums2[i]>nums2[i-1]&&nums1[i]>nums2[i-1]&&nums2[i]>nums1[i-1]){
                dp[i][0]=min(dp[i-1][1],dp[i-1][0]);//不交换的话,前一个元素可交换也可不交换,取两者的最小值
                dp[i][1]=dp[i][0]+1; //即使交换,前一个元素也可以选择交换或不交换       
            }
            //第(2)种情况
            else if(nums1[i]>nums1[i-1]&&nums2[i]>nums2[i-1]){
                dp[i][0]=dp[i-1][0];//如果不交换,前一个元素也不能交换,才能保证递增
                dp[i][1]=dp[i-1][1]+1;//如果交换,前一个元素也必须交换,才能保证递增
            }
            //第(3)种情况,这种情况没有选择, 
            //如果前一个元素选择交换,那么当前元素就不能交换,反之亦然
			else{
                dp[i][0]=dp[i-1][1];
                dp[i][1]=dp[i-1][0]+1;
            }
        }
        return min(dp[n-1][0],dp[n.size()-1][1]);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

启立家的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值