【问题标题】:How to sort an array with minimum swaps of adjacent elements如何以最小的相邻元素交换对数组进行排序
【发布时间】:2019-04-05 06:46:15
【问题描述】:

我有一个算法来解决教授必须按班级分数对学生进行排序的问题,例如 1 表示好,0 表示坏。交换次数最少,只有相邻的学生可以交换。例如,如果学生按顺序 [0,1,0,1] 给出,则只需进行一次交换即可执行 [0,0,1,1] 或在 [0,0,0,0,1,1] 的情况下, 1,1] 不需要交换。

从问题描述中我立即知道这是一个经典的最小相邻交换问题或计数反转问题,我们可以在归并排序中找到。我尝试了自己的算法以及列出的herethis site,但没有一个通过所有测试。

当我尝试以相反的顺序对数组进行排序时,通过的测试用例数量最多。我还尝试根据数组的第一个元素是 0 还是 1 按顺序对数组进行排序。例如,第一个元素是 1,那么我应该按降序对数组进行排序,否则按照学生的升序排序在任何分组中,仍然没有工作。有些测试用例总是失败。问题是当我按升序对它进行排序时,一个在反向排序的情况下失败的测试用例与其他一些测试用例一起传递,但不是全部传递。所以我不知道我做错了什么。

【问题讨论】:

  • 所有数组元素都是0还是1?没有其他值?
  • 也许问题没有解决特定的顺序,你必须选择 - 0011 或 1100 会更好?
  • 请分享“没有通过所有测试”中使用的测试
  • @GPS 是的,所有元素都是 0 或 1,没有其他值。不,我没有失败的测试用例。它对我隐藏。这正是我很难找出问题所在的原因。
  • @MBo 0011 或 1100 都可以,具体取决于哪个有最小交换。这就是我尝试按 asc/desc 顺序排序的原因。

标签: algorithm sorting mergesort


【解决方案1】:

在我看来,当涉及到 0 和 1 的数组时,术语“排序”是夸大其词。您可以简单地计算 O(n) 中的 0 和 1 并产生输出。

为了解决“最小交换”部分,我构建了一个玩具示例;我想到了两个想法。所以,例子。我们正在对学生进行排序...f:

a b c d e f
0 1 0 0 1 1

a c d b e f
0 0 0 1 1 1

如您所见,这里没有太多的排序。三个 0,三个 1。

首先,我将此视为edit distance 问题。 IE。您需要仅使用“交换”操作将abcdef 转换为acdbef。但是你是怎么想出acdbef 的呢?我的假设是,您只需将 0 和 1 拖到数组的相对两侧,而不会干扰它们的顺序。例如

        A     B     C     D
0 0 ... 0 ... 1 ... 0 ... 1 ... 1 1

0 0 0 0         ...         1 1 1 1
    A C                     B D

我不能 100% 确定它是否有效并且是否真的为您带来最少的交换。但这似乎是合理的——你为什么要为 e 花费额外的交换。 G。 A和C?

关于您应该将 0 放在第一个还是最后一个 - 我认为两次运行相同的算法并比较交换量没有问题。

关于如何找到交换的数量,甚至是交换的顺序 - 考虑编辑距离可以帮助您解决后者。仅查找交换数量也可以是编辑距离的一种简化形式。或者也许更简单的东西 - e。 G。找到离其“集群”最近的 something(0 或 1),然后移动它。然后重复,直到数组排序完毕。

【讨论】:

  • 这又不是归并排序中的交换/倒置吗?我的意思是根据我对合并排序的理解,这就是对数组进行排序的作用。我知道我只有 0 和 1,但它仍然是从根本上排序的。
  • @DashingBoy 有点,是的。我会说它更像是冒泡排序交换,而不是合并排序合并。我在答案中所做的基本上是利用数组值限制为 0 和 1 的事实,以便不进行任何排序,并可能将复杂性从 O(nlogn) 提高到 O(n)。
【解决方案2】:

如果我们必须将零排序在零之前,这将是简单的倒数计数。

def count(lst):
    total = 0
    ones = 0
    for x in lst:
        if x:
            ones += 1
        else:
            total += ones
    return total

由于在零之前排序也是一种选择,我们只需要运行这个算法两次,一次交换零和一的角色,并取最小值。

【讨论】:

  • 你能分享一下它背后的逻辑吗?似乎它只是在计算那些,但没有考虑到最小掉期。
  • @DashingBoy 第一个位置为 1 而第二个位置为 0 的每对位置都表示一次交换。我们扫描阵列,跟踪已扫描的阵列数量。每次我们达到零时,我们都会将此数字添加到总数中。
  • 我喜欢这个结果多么微小。我想有可能在我的答案和这个算法之间架起一座桥梁。肯定会遗漏几个步骤,但是将total 增加一个的数量几乎是“在数组的一端分组”的同义词。
  • 算法有问题。它适用于具有 0 次交换的 [0,0,1,1],但当序列为 [1,1,0,0] 时返回 4,而在两种情况下它都应返回 0,因为不需要交换。
  • @DashingBoy 编辑了我的答案。我们必须运行它两次,一次原样运行,一次与 if 的分支交换,然后取最小值。
猜你喜欢
  • 1970-01-01
  • 2019-08-08
  • 2019-11-14
  • 2015-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-31
  • 2015-06-28
相关资源
最近更新 更多