【问题标题】:Judgecode -- Sort with swap (2)Judgecode——交换排序(二)
【发布时间】:2016-12-02 03:57:25
【问题描述】:

我看到的问题如下,有人对此有所了解吗? http://judgecode.com/problems/1011

给定从 0 到 n - 1 的整数排列,对它们进行排序很容易。但是如果每次只能交换一对整数呢?

请计算最小交换次数

【问题讨论】:

    标签: algorithm jobs


    【解决方案1】:

    一种经典算法似乎是置换循环 (https://en.wikipedia.org/wiki/Cycle_notation#Cycle_notation)。所需的交换次数等于元素总数减去循环次数。

    例如:

    1 2 3 4 5
    2 5 4 3 1
    
    Start with 1 and follow the cycle:
    1 down to 2, 2 down to 5, 5 down to 1.
    
    1 -> 2 -> 5 -> 1
    3 -> 4 -> 3
    

    我们需要将索引 1 与 5 交换,然后将索引 5 与 2 交换;以及索引 3 和索引 4。总共 3 个交换或n - 2。我们将循环数减去n,因为循环元素加在一起的总数为n,并且每个循环表示一个交换小于其中的元素数。

    【讨论】:

      【解决方案2】:

      这是C 中针对上述问题的一个简单实现。该算法类似于用户 גלעד ברקן

      • a[]的每个元素的位置存储在b[]中。所以,b[a[i]] = i
      • 从左到右迭代初始数组a[]
      • 在位置i,检查a[i] 是否等于i。如果yes,则继续迭代。
      • 如果no,那么是时候交换了。仔细查看代码中的逻辑以了解交换是如何发生的。 这是最重要的一步,因为数组a[]b[] 都需要修改。 增加交换的count

      这里是实现:

      long long sortWithSwap(int n, int *a) {
        int *b = (int*)malloc(sizeof(int)*n);  //create a temporary array keeping track of the position of every element
        int i,tmp,t,valai,posi;
        for(i=0;i<n;i++){
          b[a[i]] = i;
        }
        long long ans = 0;
        for(i=0;i<n;i++){
          if(a[i]!=i){
            valai = a[i];
            posi = b[i];
            a[b[i]] = a[i];
            a[i] = i;
            b[i] = i;
            b[valai] = posi;
            ans++;
          }
        }
        return ans;
      }
      

      【讨论】:

        【解决方案3】:

        解决这个问题的本质在于以下观察
        1.数组中的元素不重复
        2.元素的范围是从0到n-1,其中n是数组的大小。

        方法
        在您了解了解决问题的方法之后,您可以在线性时间内解决它。

        想象一下,在对所有条目进行排序后,数组会是什么样子?
        对于所有条目,它看起来像 arr[i] == i。这有说服力吗?

        首先创建一个名为 FIX 的 bool 数组,其中 FIX[i] == true 如果第 i 个位置是固定的,则初始化这个数组为 false

        开始检查原始数组是否匹配 arr[i] == i,直到这个条件成立,一切都好。在继续遍历数组的同时,还要更新 FIX[i] = true。
        当你发现 arr[i] != i
        你需要做一些事情时, arr[i] 必须有一些值 x这样 x > i,我们如何保证?保证来自数组中的元素不重复这一事实,因此如果数组排序到索引 i 则意味着数组中位置 i 处的元素不能来自左侧,而是来自右侧。
        现在值 x 本质上是在说某个索引,为什么会这样,因为数组只有从 0 开始的 n-1 的元素,并且在排序后的数组中,数组的每个元素 i 都必须位于位置 i。
        arr[i] == x 的意思是,不仅元素 i 不在它的正确位置,而且元素 x 从它的位置丢失。 现在要修复第 i 个位置,您需要查看第 x 个位置,因为可能第 x 个位置包含 i,然后您将交换索引 i 和 x 处的元素,并完成工作。
        但是等等,索引没有必要x 将持有 i (您只需 1 次交换即可完成这些位置的修复)。相反,索引 x 有可能保存值 y,它再次大于 i,因为数组只排序到位置 i。
        现在在你可以固定位置 i 之前,你需要固定 x,为什么?我们稍后会看到。
        因此,现在您再次尝试修复位置 x,然后类似地您将尝试修复,直到您在某个位置看不到元素 i 时。
        时尚是跟随 arr[i] 的链接,直到你在某个索引处点击元素 i。
        以这种方式跟随,保证你一定会在某个位置打到i。为什么 ?试着证明它,做一些例子,你会感觉到的
        现在您将开始修复您在从索引 i 到该索引(比如 j)的路径中看到的所有索引。现在你看到的是你所遵循的路径是一个循环路径,对于每个索引 i,arr[i] 在它的前一个索引处被撕裂(从你到达这里的索引),一旦你看到你可以修复索引,并将 FIX 数组中的所有索引标记为真。现在继续数组的下一个索引并做同样的事情,直到整个数组被修复..
        这是完整的想法,但只能说不。对于交换,您会发现,一旦找到 n 个元素的循环,就需要 n 个交换,然后修复数组,然后再次继续。所以这就是你将如何计算没有。掉期。 如果您对该方法有任何疑问,请告诉我。 您也可以要求 C/C++ 代码帮助。
        乐于助人 :-)

        【讨论】:

          猜你喜欢
          • 2017-05-05
          • 2013-07-08
          • 1970-01-01
          • 2012-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-14
          • 2017-02-24
          相关资源
          最近更新 更多