动态规划—使序列递增的最小交换次数(leetcode 801)

该博客主要讨论了一种动态规划的解决方案,用于找出使两个长度相等的整数数组在交换最少次数后保持严格递增的策略。通过对不同状态的分析,确定了状态转移方程,并通过优化减少了空间复杂度。最终,实现了O(N)的时间复杂度和O(1)的空间复杂度的算法。
摘要由CSDN通过智能技术生成

题目描述

我们有两个长度相等且不为空的整型数组 A 和 B 。

我们可以交换 A[i] 和 B[i] 的元素。注意这两个元素在各自的序列中应该处于相同的位置。

在交换过一些元素之后,数组 A 和 B 都应该是严格递增的(数组严格递增的条件仅为A[0] < A[1] < A[2] < ... < A[A.length - 1])。

给定数组 A 和 B ,请返回使得两个数组均保持严格递增状态的最小交换次数。假设给定的输入总是有效的。

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

注意:

    A, B 两个数组的长度总是相等的,且长度的范围为 [1, 1000]。
    A[i], B[i] 均为 [0, 2000]区间内的整数。

问题分析

确定状态

动态规划一般来讲,目标是求什么则什么即为状态,然后分析当前状态和之前状态的推导关系,进而进行穷举所有状态即可。
本题中使用dp[i][j] 表示第 i 个位置的元素,第 j (交换、不交换)状态时的最小次数。
初始状态

第 0 个位置可以交换,也可以不交换,即初始状态为:d[0][0] = 0、dp[0][1] = 1。
状态转移方程

根据题目要求一定存在结果,所以在第 i 个位置,只会有以下几种情况:
①.A、B 两个数组对应的位置都是有序、存在交叉

如上图,A[i-1] < A[i] 、B[i-1] < B[i],并且 A[i-1] < B[i] 、B[i-1] < A[i];此时位置 i 可以交换,也可以不交换,并且和上个位置的交换状态无关。
②.A、B 两个数组对应的位置都是有序、不在交叉

如上图,A[i-1] < A[i] 、B[i-1] < B[i],并且 A[i-1] < B[i] 、B[i-1] > A[i];此时位置 i 若选择不交换,则上个位置也不能交换、若选择交换,则上个位置也必须交换。
③.A、B 两个数组对应的位置有一个存在无序

如上图,A[i-1] > A[i] 、B[i-1] < B[i],并且 A[i-1] < B[i] 、B[i-1] < A[i];此时位置 i 若选择不交换,则上个位置必须交换、若选择交换,并且上个位置不能交换。
确认结果

数组末尾位置的状态值就是本题为结果,即 min(dp[A.size()-1][0],dp[A.size()-1][1]);

代码

class Solution {
public:
    int minSwap(vector<int>& A, vector<int>& B) {
        int res = 0;
        vector<vector<int>> dp(A.size(),vector(2,0));
        dp[0][0] = 0;
        dp[0][1] = 1;
        for(int i = 1;i < A.size();i++)
        {
            if(A[i-1]<A[i]&&B[i-1]<B[i]){
                if(A[i-1]<B[i] && B[i-1]<A[i]){//任意交换或者不交换,取最优值
                    dp[i][0] = min(dp[i-1][0],dp[i-1][1]);
                    dp[i][1] = min(dp[i-1][0],dp[i-1][1])+1;
                }else{
                    dp[i][0] = dp[i-1][0];//不交换,则上个位置也不能交换
                    dp[i][1] = dp[i-1][1]+1; //交换,则上个位置也必须交换
                }
            }else{
                dp[i][0] = dp[i-1][1];// 不交换,则上个位置必须交换
                dp[i][1] = dp[i-1][0]+1;// 交换,则上个位置不能交换
            }
        }
        return min(dp[A.size()-1][0],dp[A.size()-1][1]);
    }
};

优化  我们发现dp[i][] 只和 dp[i-1][]有关系,定义两个变量代表上次的dp_0,dp_1

 

class Solution {
public:
    int minSwap(vector<int>& nums1, vector<int>& nums2) {

        // vector<vector<int>> dp(nums1.size(), vector<int>(2,0));

        // dp[0][0] = 0;
        // dp[0][1] = 1;
        int pre_0 = 0;
        int pre_1 = 1;
        int cur_0 = pre_0;
        int cur_1 = pre_1;
        for(int i = 1; i < nums1.size(); ++i) {

            if(nums1[i-1] < nums1[i] && nums2[i-1] < nums2[i]) {
                if(nums1[i-1] < nums2[i] && nums2[i-1] < nums1[i]) {
                    cur_0 = min(pre_0, pre_1);
                    cur_1 = min(pre_0, pre_1) + 1;
                } else {
                    cur_0 = pre_0;
                    cur_1 = pre_1 + 1;
                }
            } else {
                cur_0 = pre_1;
                cur_1 = pre_0 + 1;
            }
            pre_0 = cur_0;
            pre_1 = cur_1;
        }
        return min(cur_0, cur_1);

    }
};

复杂度分析

  • 时间复杂度:O(N)。

  • 空间复杂度:O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值