【问题标题】:Minimum number of adjacent swaps of binary array二进制数组的最小相邻交换次数
【发布时间】:2019-11-14 15:44:38
【问题描述】:

给定一个二进制数组,找出将 1 和 0 分组所需的最小相邻交换数。

示例:

Input : 0,1,0,1 (array with 0 based index)
Swaps needed : 0,1,0,1 -> 0,0,1,1 (1 swap from index 1 to index 2)

Solution : 1

示例:

Input : 1,0,1,0,0,0,0,1
Swaps needed : 
1,0,1,0,0,0,0,1 -> 1,1,0,0,0,0,0,1 -> 1,1,0,0,0,0,1,0 -> 1,1,0,0,0,1,0,0 -> 1,1,0,0,1,0,0,0 -> 1,1,0,1,0,0,0,0 -> 1,1,1,0,0,0,0,0

Total 6 swaps so the solution is 6.

1 和 0 可以位于开头或结尾,但它们应位于一个位置,即开头或结尾。

我为此要求提出了以下逻辑。我在hackerrank中尝试了这个,它对一个隐藏的测试用例失败了,并且给了3个测试用例超时,因为我的代码中有嵌套循环。

static int countSwaps(List<Integer> list) {
    int temp;
    int swaps = 0;
    int n = list.size();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n - 1; j++) {
            if ((list.get(j) == 0) && (list.get(j + 1) == 1)) {
                temp = list.get(j);
                list.set(j, list.get(j + 1));
                list.set(j + 1, temp);
                swaps++;
            }
        }
    }

    return swaps;
}

解决这个程序的更好方法是什么?

我已经浏览过这篇帖子Given an array of 0 and 1, find minimum no. of swaps to bring all 1s together (only adjacent swaps allowed),但答案没有给出正确的输出。

【问题讨论】:

  • 超时的原因是您实际上是手动进行交换操作,即 O(n^2)。有一种数学方法可以在不实际执行操作的情况下计算交换次数。不幸的是,我不知道这个功能,但是this solves it。不是 O(n^2),而是 O(2n) -> O(n)。
  • @Compass,我看到链接是针对Sort Binary array,所以它总是尝试将0放在第一位。但在我的情况下,第一位可以被 0 或 1 占据
  • 有一种方法可以确定排序方式,但您也可以在 O(4n) -> O(n) 处进行两种排序,并取较低的值,直到找出该公式。很确定它只是在计算哪一方有更多的#s要移动。

标签: java algorithm


【解决方案1】:

要将所有 1 向左移动,设 p(i) 是从左到右的第 i 个 1 的位置。它最终需要移动到位置 i。这将需要 p(i) - i 交换。只需为所有 i 总结这个数量。

int countSwaps(int [] a) {
  int n = 0, i = 0;
  for (int p = 0; p < a.length; ++p)
    if (a[p] == 1) {
      n += p - i;
      ++i;
    }
  return n;
}

向右移动是对称的。做类似的计算并取最小值。

【讨论】:

  • 谢谢,我无法理解所提供的解释,你能解释一下这个逻辑是如何工作的吗?
  • 这很好,只是它不能编译。
  • 这很好,但只完成了一半的挑战。 "1 和 0 可以位于开头或结尾" 例如输入 1,0,1,0,0,0,0,1 返回 6,但输入 1,0,0,0,0,1,0,1 返回 9,而真正的答案也是 6,因为您只需将 1 向右而不是向左移动以获得有效结果。
  • @Gene,根据我的理解,这个逻辑一直把1's放在开头,但在我的情况下,它们也可以放在最后。
  • @learner 抱歉,我错过了关于开始或结束的部分。同样的想法也适用。只需计算两者并像 Andreas 一样取最小值。
【解决方案2】:

answer by Gene 为基础,修复编译错误并支持将 1 向左移动(到开头)将它们向右(到末尾)移动,也就是将 0 向左移动:

static int countSwaps(int... a) {
    int n0 = 0, i0 = 0, n1 = 0, i1 = 0;
    for (int p = 0; p < a.length; ++p) {
        if (a[p] == 0)
            n0 += p - i0++; // No. of steps to move the 0 to the left
        else
            n1 += p - i1++; // No. of steps to move the 1 to the left
    }
    return Math.min(n0, n1); // Choose lowest no. of steps
}

测试

System.out.println(countSwaps(0,1,0,1));
System.out.println(countSwaps(1,0,1,0,0,0,0,1));
System.out.println(countSwaps(1,0,0,0,0,1,0,1));

输出

1
6
6

【讨论】:

    【解决方案3】:

    这是我的解决方案(Java):

    public static int minSwaps(int[] arr) {
        int min_swaps1 = 0;
        int zero_counts = 0;
        int min_swaps2 = 0;
        int one_counts = 0;
    
        for (int j : arr) {
            if (j == 0) {
                zero_counts++;
                min_swaps2 += one_counts;
            } else {
                one_counts++;
                min_swaps1 += zero_counts;
            }
        }
    
        return Math.min(min_swaps1, min_swaps2);
    }
    

    【讨论】:

    • 问题是关于 Java,而不是 Python。
    猜你喜欢
    • 1970-01-01
    • 2019-08-08
    • 2023-04-03
    • 1970-01-01
    • 2015-01-06
    • 2020-04-22
    • 2017-12-20
    • 2010-09-23
    • 1970-01-01
    相关资源
    最近更新 更多