【问题标题】:Correctness Of Minimum Number Of Swaps To Sort An Array对数组排序的最小交换次数的正确性
【发布时间】:2018-07-08 02:12:23
【问题描述】:

问题来自这里:https://www.geeksforgeeks.org/minimum-number-swaps-required-sort-array/

我将在下面重复: 给定一个包含 n 个不同元素的数组,找出对数组进行排序所需的最小交换次数。

例子:

输入:{4, 3, 2, 1} 输出:2 解释 : 将索引 0 与 3 和 1 与 2 交换为 形成排序数组 {1, 2, 3, 4}。

输入:{1, 5, 4, 3, 2} 输出:2

我已经通过执行以下操作解决了这个问题。

  1. 对数组排序 (n log(n)) 时间
  2. 当我比较排序后的数组和原始数组时,创建一个散列来跟踪所需的交换。这应该是另一个 O(n) 时间

总时间复杂度应该是:O(n + (n log n)) = O(n log(n))

以下是我为此编写的代码,它适用于提供的测试用例。

def solution(array)

  sorted = array.sort
  puts array.inspect
  puts sorted.inspect

  counter_parts_that_have_been_seen = {}

  number_of_swaps_required = 0

  array.each_with_index do | val, idx |
    if counter_parts_that_have_been_seen[val] == true
      next
    end

    array_val = val
    sorted_val = sorted[idx]

    if array_val != sorted_val
      puts "A swap will be required: array val is #{array_val} and sorted_array_val is #{sorted_val}"
      number_of_swaps_required += 1
      counter_parts_that_have_been_seen[sorted_val] = true
    end
  end

  puts "Number of swaps required are: #{number_of_swaps_required}"

end

现在,我的问题是,如何验证正确性?我不知道这种方法是正确的。

有人能解释一下吗?

【问题讨论】:

  • 我还没有真正理解您的代码,但它适用于 {3,1,2} 吗?请注意,该输入需要两次交换位置和值。
  • 好吧,对于那个输入,它提供了 2 次交换。现在,即使在技术上这是正确的。我不知道我的代码是否以正确的方式到达那里。因为,我的代码假定一旦进行交换,交换的元素就处于正确的位置。但 {3, 1, 2} 并非如此。所以换句话说,让我们扩展这个问题:如何证明一个特定的答案是正确的?
  • Nswaps = Nout_of_place - Ncycles。所以问题可以归结为寻找 out_of_place 元素和循环次数。
  • 您是只想找到最少的交换次数,还是以最有效的方式进行排序?
  • @FDavidov 只是问题状态的最小交换次数。以最有效的方式排序将是 O(n log(n))。数组是什么样的并不重要。

标签: algorithm sorting correctness


【解决方案1】:

从未排序数组中的第一个元素开始,检查它是否在正确的位置,如果不是,则将正确的值交换到该位置。测试可以像您一样通过与集合的排序版本进行比较来完成,也可以将所选元素与它后面的每个元素进行比较。

随着您的进行,您可能会遇到位于正确位置的元素 - 要么是因为它们从正确的位置开始,要么是在放置较早的元素时它们被交换到了那里(最后一个元素必须是在所有其他元素都被放置的时候)放置)。只需将它们留在原处并移动到下一个元素。

使用此方法,每个交换都正确放置至少一个元素,一些交换将正确放置两者。

一个位于正确位置的元素可以忽略问题 - 永远不需要将它从正确的位置移动来对任何其他元素进行排序。 还有一对彼此放置的元素(例如 {3,2,1} 中的 3 和 1 )永远不需要与任何其他元素交换。它们形成了自己独立的元素集。

一旦你有一种方法,如上所述,获得正确答案,它显然可以用来评估任何替代方法。

【讨论】:

  • 但我的问题是:如何知道答案是正确的?如,这些是交换的最小数量?对于一百万个数字的数组,如果答案是 12213,除非有方法证明,否则我无法知道这个答案是否正确和最优。这就是我的问题所在。
  • 您可以使用归纳证明。在开始时对不需要交换的任何元素进行折扣,对于 n 个元素,上述方法将应该放在首位的元素交换到首位,在其后留下 n-1 个元素。考虑将它们按顺序交换的最佳方法。添加第 n 个元素无法减少该数量,也无法避免所需的额外交换。
【解决方案2】:
Index :   0   1   2   3   4   5   6   7   8   9
------+-----+---+---+---+---+---+---+---+---+--
Array :   1  22  32  42  12  83  64  93  73  53
------+-----+---+---+---+---+---+---+---+---+--
          A  BBBBBBBBBBBBBB  CC  DD  CCCCCCCCCC
Target:   0   2   3   4   1   8   6   9   7   5
Diffs :   0   1   1   1  -3   3   0   2  -1  -4
Source:   0   4   1   2   3   9   6   8   5   7

在这个例子中,array[] 需要排序。

  • Target 是排序后该位置的索引
  • source 是该索引应该从中获取其值的位置
  • diffs 是该索引处的项目在排序过程中的相对移动

您可以看到四个(循环)组:

  • A : 1 个成员1
  • B : 4 名成员{22,32,42,12}
  • C:4 名成员:{83,93,73,53}
  • D:1 名成员:64

具有 1 个成员的组已排序:需要零交换。 有 4 个成员的组可以用 4 个交换进行排序。 (最后的交换将 两个 元素放到它们的最终位置) 所以需要的交换次数是0+3+3+0

现在你只需要证明你可以在 N-1 次交换中排序一个 N 循环...

【讨论】:

    【解决方案3】:

    如果有一个元素不在正确的位置,那么也一定有另一个元素不在它的正确位置(第一个元素需要放置在另一个元素所占据的其他位置) .如果这以图形的形式表示,则没有正确元素的位置将有一条边朝向它,而一条边距它。这将最终形成一个或多个循环。现在,循环中元素的位置都在该循环内。因此,我们现在需要证明,如果一个循环中有“n”个元素,则需要最少“n-1”个交换来对它们进行排序。 我们可以证明这是归纳法。

    基数:n=1
    只有一个元素,所以已经排序(微不足道)。这意味着 0 次交换,即 n-1 => 1-1 = 0

    假设一个循环中有k个元素,则需要min k-1 swaps

    k+1 个元素
    循环中的元素具有朝向它需要的位置的边缘。这个位置对另一个位置有另一个优势。现在,如果我们交换前一个元素,我们将删除前一个边,而后一个元素会转到交换位置。现在我们剩下一个大小为 (k+1)-1 = k 的循环。通过归纳,k 周期需要 k-1 次交换。因此,k+1 将需要 (k-1)+1 = k 次交换。

    【讨论】:

      猜你喜欢
      • 2019-08-08
      • 2015-01-06
      • 1970-01-01
      • 2013-02-15
      • 1970-01-01
      • 2017-01-09
      • 2017-12-20
      • 2015-02-18
      相关资源
      最近更新 更多