【问题标题】:Minimum swaps to relative sort two arrays最小交换到相对排序两个数组
【发布时间】:2018-08-03 15:22:50
【问题描述】:

给定两个数组arr1arr2,我们必须找到最小交换来将两个数组相对排序为严格递增的顺序。如果无法进行相对排序,则返回 -1。

相对排序定义为交换arr1arr2的相同索引元素。

即相对排序的步骤:

swap(arr1[i], arr2[i])

而严格递增的顺序定义为:

arr[i+1]>arr[i] for all i

例子:

arr1={1,4,4,9} 
arr2={2,3,5,10}

那么最小交换为 1,因为交换 arr1[2]arr2[2],将使两个数组都严格增加。 我使用递归解决了这个问题。 如果arr[i]>arr[i+1],我们可以交换索引i的元素或索引i+1的元素,然后调用索引i+1的函数。我试图找到两个值中的最小值并返回它。对i 的每个索引都遵循此过程。

int f(int N, int *arr1, int *arr2, int i){
    if(i == N-1)
        return 0;
     if(arr1[i]>=arr1[i+1] && arr2[i]>=arr2[i+1])return -1;
    if(arr1[i]>=arr1[i+1] || arr2[i]>=arr2[i+1]){
        int m, n;
        swap(arr1[i], arr2[i]);
        m = f(N, arr1, arr2, i+1);
        swap(arr1[i], arr2[i]);
        swap(arr1[i+1, arr2[i+1]);
        n = f(N, arr1, arr2, i+1);
        if(m == -1 && n==-1)return -1;
        if(m==-1)return n;
        if(n==-1)return m;
        return min(m, n);
    }
    return f(N, arr1, arr2, i+1);
 }

int minSwaps(int N, int *arr1, int *arr2){
    return f(N, arr1, arr2, 0);
}

由于这是我在在线编码测试中遇到的问题,我通过了基本的测试用例,但我仍然不确定这种方法是否适用于所有测试用例。

另外,我想知道这个问题是否可以使用动态编程来解决。如果是,表中应该存储什么状态?应该采用什么方法?

【问题讨论】:

  • this link 是否与您在帖子中询问的内容相似?
  • @LAD 不,不是。我正在编辑问题以包含一个示例
  • 如果无法进行相对排序,那么我们必须返回 - 1
  • @LAD 是的,OP 需要对此进行更多说明。即使最多有 2 个重复整数,也可能存在不可能的状态。喜欢[1,5,9][2,3,3]。我也觉得让我们假设如果只给出有效的输入,那么这个问题并不像看起来那么棘手。
  • @Nisha 这是有道理的。您可能想在帖子中说明这一点。

标签: arrays algorithm sorting


【解决方案1】:
int minSwap(vector<int>& a, vector<int>& b){
    int inf = (int)(1e9);
    int n=a.size();
    int dp[n][2];
    dp[0][0]=0;
    dp[0][1]=1;
    for(int i=1;i<n;i++)
        dp[i][0]=dp[i][1]=inf;
    for(int i=1;i<n;i++){
        if(a[i-1]<a[i]&&b[i-1]<b[i]){
            dp[i][0]=dp[i-1][0];
            dp[i][1]=dp[i-1][1]+1;
        }
        if(a[i-1]<b[i]&&b[i-1]<a[i]){
            dp[i][0]=min(dp[i][0],dp[i-1][1]);
            dp[i][1]=min(dp[i][1],dp[i-1][0]+1);
        }
    }
    return min(dp[n-1][0],dp[n-1][1]);
}

【讨论】:

    【解决方案2】:

    您的解决方案是数组大小的指数。正如您在问题中注意到的那样,可以使用动态规划获得解决方案。

    首先,让我们定义一个辅助函数来检查我们交换i-th and/or i + 1-st 元素后是否获得了本地有效的解决方案。我所说的本地有效的意思是只考虑这四个数字。

    def isValid(i, preSwap, postSwap):
      val lx = if (preSwap) y(i) else x(i)
      val rx = if (postSwap) y(i + 1) else x(i + 1)
      val ly = if (preSwap) x(i) else y(i)
      val ry = if (postSwap) x(i + 1) else y(i + 1)
      // x(i) < x(i + 1) && y(i) < y(i + 1)
      lx < rx && ly < ry
    

    现在,我们将简单地向后循环数组。我们的动态编程内存将是恒定的——我们只需要记住两个整数。让我们考虑 i-thi = x.length - 2 downto 0 的迭代。

    • 最佳交换次数是多少,以便索引 i + 1 upto x.length - 1 越来越多地排序,x(i)y(i)不交换
    • 最佳交换次数是多少,以便索引i + 1 upto x.length - 1 越来越多地排序并且x(i)y(i)交换

    对于长度为1 的列表,我们获得一个元组(prevNoSwap, prevSwap) = (0, 1)。我们的循环步骤将考虑四种情况:

    • 我们不会在i 交换,我们不会在i + 1 交换;最佳:prevNoSwap,
    • 我们在i 交换,我们不在i + 1 交换;最佳:prevNoSwap + 1,
    • 我们不在i 交换,我们在i + 1 交换;最佳:prevSwap,
    • 我们在i 交换,我们不在i + 1 交换;最佳:prevSwap + 1

    如果给定的案例创建了有效的解决方案,我们会将其视为可能的步骤数。我们将它们按swapping / not swapping 分组到i 并取最小值。如果在特定情况下无法找到解决方案,我们假设这些元素中的任何一个都可能变为 Infinity

    在循环之后,我们至少选择两个元组值。下面是其余的伪代码:

    state = (0, 1)
    for i in x.length - 2 downto 0
      noPreSwap, withPreSwap = [#INFINITY], [#INFINITY]
    
      if (isValid(i, preSwap = false, postSwap = false)) noPreSwap += state.left
      if (isValid(i, preSwap = false, postSwap = true)) noPreSwap += state.right
      if (isValid(i, preSwap = true, postSwap = true)) withPreSwap += state.right + 1
      if (isValid(i, preSwap = true, postSwap = false)) withPreSwap += state.right
    
      state = (noPreSwap.min(), withPreSwap.min())
    return if state.min().isInfinity() -1 else state.min()
    

    【讨论】:

    • 您好,谢谢您的回答。尽管我理解了大部分内容,但我感到困惑,因为我不熟悉编写过于复杂的伪代码。这里没有 PreSwap 和 withPreSwap 数组吗?
    猜你喜欢
    • 2019-08-08
    • 2020-02-03
    • 1970-01-01
    • 2015-01-06
    • 2018-07-08
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多