使序列递增的最小交换

我们有两个长度相等且不为空的整型数组 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]区间内的整数。

思路分析:这道题的确实有点难度,对于分析归纳能力要求挺高的。
刚开始吧,可能大家都想着使用类似贪心策略,就是遇到A[i - 1] >= A[i]这种逆序的时候,我们就将A[i]和B[i]进行交换,这时大家都会被一个测试示例难倒

0   4   4   5
0   1   6   8

第一次遇到A[i - 1] >= A[i]时,i = 2,按照贪心策略,我们应该交换A[2]和B[2],交换之后我们又发现A[3]出现了逆序,接着有需要交换A[3]和B[3],所以总共需要两次交换。蛋式这道题只需要交换1次,即我们交换A[1]和B[1]即可同时达到A、B严格递增。因此这种简单的贪心策略行不通。

经过查阅别人的实现,发现了一种动态规划的方法。

swapVec[ i ] 表示第 i 个元素进行交换,使A[0, i],B[0,i]严格单调递增的最小交换次数
keepVec[ i ] 表示第 i 个元素不进行交换,使A[0, i],B[0,i]严格单调递增的最小交换次数。

现在的问题就是我们如何找到状态转移方程。

(1)如果A[ i ] > A[ i - 1 ] && B[ i ]> B[ i - 1 ],对于这种情况,本身就是递增的,本不需要进行交换A[i]和B[i]
		swapVec[ i ]表示强制交换A[i]、B[i]即交换第i个元素,那么前一个位置i-1也要交换,同时交换才能继续保证同时递增,所以swapVec[ i ] = swapVec[ i - 1 ]+1
		keepVec[ i ]表示不交换A[i]、B[i],即不交换第i个元素,则第i-1个元素也不需要交换,keepVec[ i ]=keepVec[ i - 1 ]
(2)如果A[ i ] > B[ i - 1 ] && B[ i ]> A[ i - 1 ],对于此种情况,必须要交换A[i]、B[i]才能保持递增
		swapVec[i]正好也是要交换当前位置,而前一个位置不能交换,那么swapVec[ i ] = keepVec[ i - 1 ] +1
		keepVec[ i ]是不能交换当前位置,那么我们可以通过交换前一个位置来同样实现递增,即keepVec[ i ] = swapVec[ i - 1 ]
如果两种情况均成立时取较小值。

 

class Solution {
public:
    int minSwap(vector<int>& A, vector<int>& B) {
        int numsSize = A.size();
        //swapVec[ i ] 表示第 i 个元素进行交换,使A[0, i],B[0,i]严格单调递增的最小交换次数
    	//keepVec[ i ] 表示第 i 个元素不进行交换,使A[0, i],B[0,i]严格单调递增的最小交换次数。
        vector<int> swapVec(numsSize, INT_MAX), keepVec(numsSize, INT_MAX);
        swapVec[0] = 1;//初始化
        keepVec[0] = 0;
        for (int index = 1; index < numsSize; ++index){
            if (A[index] > A[index - 1] && B[index] > B[index - 1]){
                //如果第 i 个元素交换,那么第 i - 1 个元素一定是交换的;如果第 i 个元素没有交换,那么第 i - 1个元素一定没有交换
                swapVec[index] = swapVec[index - 1] + 1;
                keepVec[index] = keepVec[index - 1];
            }
            if (A[index] > B[index - 1] && B[index] > A[index - 1]){
                //如果第 i 个元素交换,那么第 i - 1 个元素一定是没有交换的;如果第 i 个元素没有交换,那么第 i - 1个元素一定是交换的
                swapVec[index] = min(swapVec[index], keepVec[index - 1] + 1);
                keepVec[index] = min(keepVec[index], swapVec[index - 1]);
            }
        }
        return min(swapVec.back(), keepVec.back());
    }
};

转载:https://blog.csdn.net/qq_41855420/article/details/90264842




原文地址:https://www.cnblogs.com/wuchanming/p/12237298.html

时间: 2024-10-11 10:50:13

使序列递增的最小交换的相关文章

[微软]有两个序列a,b,大小都为n,序列元素的值任意整数,无序; 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小_利用排列组合思路解决_python版

(原题出自微软公司面试题)问题如下:有两个序列a,b,大小都为n,序列元素的值任意整数,无序:要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小.例如:a=[100,99,98,1,2, 3]b=[1, 2, 3, 4,5,40] 题目是看到QQ群友发的,网上也百度了下目前已经有好几种解法了.写了半天有点晕,后面忽然想到中学时候数学里面的排列组合的方法.方法对于较短的list可行,长list组合情况太多,可能耗时太长或溢出. 1 from itertools im

通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小

题目描述: 有两个序列a,b,大小都为n,序列元素的值任意整数,无序:要求:通过交换a,b 中的元素,使[序列a 元素的和]与[序列b 元素的和]之间的差最小.例如:var a=[100,99,98,1,2, 3];var b=[1, 2, 3, 4,5,40]; 分析: 很多情况下,贪心算法得到的解并不是最优解,但是这道题貌似是最优解 思想:每次从AB中找到两个使得和之差最小的元素交换 当前和之差diff=sumA-sumB,从A中找到一元素a,从B中找到一元素b,如果交换那么就须有(sumA

hdu 4882 /按排顺序使序列最优问题

题意: 安排一个序列,该序列每个数有俩个属性:t[i].val[i].计算一个点的价值:到目前为止的总时间*val[i].,,求  安排顺序后使得 计算所有点的价值之和最小. 思路:对于任意相邻俩项,考虑他俩顺序对总体的影响:前面的和后面的必然不变,设 他俩为 i,j.  俩种情况作差得:t/val小,就小.所以可以按之排序,则总体最小. #include<iostream> #include<vector> #include<algorithm> using name

Effective Item 9 - 尽量使可访问性最小化

模块设计是否良好,有个重要的因素在于,相对外部模块是否隐藏内部数据以及实现细节. 设计良好的模块会隐藏实现细节,并将API与其实现隔离开来. 模块之间通过API进行通信,对于内部工作情况互不可见. 即,封装(encapsulation)--软件设计的基本原则之一. 为什么要封装? 通过封装可以有效地接触各个模块之间的耦合关系,使这些模块可以独立地开发.测试.优化.使用.理解和修改. 即: ·可以增加开发效率,模块可以并行开发. ·封装可以减轻维护的负担,可以更有效的进行优化,且不会影响其他模块的

neu 1493 Caoshen like math(最小交换次数)

http://acm.neu.edu.cn/hustoj/problem.php?cid=1047&pid=4 题意:数字1到n 任意排列 求排列成有序序列最少交换次数 思路:求最小交换次数有两种 1 交换的两数必须相邻  (poj 2299) 通过归并排序求出其逆序数即为所求值 证明:可以先将最大数交换到最后,由于是相邻两个数交换,需要交换的次数为最大数后面的数的个数(可以看做是最大数的逆序数),然后,交换过后,去除最大数,再考虑当前最大数也需要其逆序数次交换.则每个数都需要交换其逆序数次操作

关于一个求最小交换次数的算法的一个严格证明,是严格证明,不是想当然

问题描述: 有一个1~n的数列的排列,但是这个数列已经被打乱了排列顺序,如果我们只是通过"交换任意两个元素",那么,要实现元素从1~n的有序排列,"最少的交换次数是多少?" 解答过程: 首先我们纸上可以先写写简单的情况试试,比如排列:4 3 1 2, 交换次数=3:我们可以在多组测试中,边测试边想,真正的实现需要满足:4本该到2处, 2本该到3处, 3本该到1处, 1本该到4处,刚好一个循环. 于是,考虑: 引理:是否对于满足这种一个循环的排列,最少交换次数等于元素

【Leetcode】使数组唯一的最小增量(每日一题)

题目链接:使数组唯一的最小增量 题意:给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1. 返回使 A 中的每个值都是唯一的最少操作次数. 题解: 1.暴力sort.O(nlogn).排序以后,如果当前数字<=前一个数字,那么就把当前的数字变成前一个数字+1. 增量就是A[i-1]+1-A[i].遍历以后的结果就是要求的最小增量.跑了80ms 2.用一个数组表示hash.空间换时间.O(n). 我们对hash数组进行移动操作,每次对hash[i]>1的数字进行操作,只

”高精度整数删去若干位以使剩下的值最小“问题

问题描述: 键盘输入一个高精度的正整数N(不超过240位) ,去掉其中任意M个数字后剩下的数字按原左右次序将组成一个新的正整数. 编程对给定的N和M,寻找一种方案使得剩下的数字组成的新数最小.输出组成的新的正整数. 输入数据均不需判错. 如果去掉了某几个位后得到的新整数开头为0,保留0. 输入: 本题有多组测试数据,每组测试数据占一行. 一个高精度正整数N(N不超过240位)一个正整数M.(M为不大于N的长度的正整数) N,M由一个空格分开. 456547 1 456547 2 456547 3

Heap:左式堆的应用例(任意序列变单调性最小价值)

首先来说一下什么是左式堆: A:左式堆是专门用来解优先队列合并的麻烦(任意二叉堆的合并都必须重新合并,O(N)的时间). 左式堆的性质: 1.定义零路经长:节点从没有两个两个儿子节点的路经长,把NULL定义为-1 2.堆性性质(x的键值比x左右两个儿子节点的键值要大或者要小) 3.堆中的每一个节点x,左儿子的零路经长至少与右儿子的零路经长一样长. 4.节点的距离等于右节点的距离+1. 引理: 若左式堆的距离定义为一定值,则节点数最少的左式堆是完全二叉堆. 定理: 若左式堆的距离为k,则这棵树最少