Algorithm 隔离0和1列表所需的最小相邻掉期数量是多少?

Algorithm 隔离0和1列表所需的最小相邻掉期数量是多少?,algorithm,data-structures,Algorithm,Data Structures,我试图解决一个数据结构和算法问题,即给定一组1和0,将数字分组,使所有0都在一起,所有1都在一起。如果一个人只能交换两个相邻的元素,那么实现这一点所需的最小交换次数是多少?哪一组在哪一端并不重要 例如: [0,1,0,1]=[0,0,1,1]1掉期 [1,1,1,1,0,1,0]=[1,1,1,1,1,0,0]1掉期 [1,0,1,0,0,0,1]==[1,1,1,0,0,0,0,0]6次互换 请注意,这与此处提出的问题不同: 我没有对数组进行排序,我只是尝试将所有0和所有1组合在一起,而不管

我试图解决一个数据结构和算法问题,即给定一组1和0,将数字分组,使所有0都在一起,所有1都在一起。如果一个人只能交换两个相邻的元素,那么实现这一点所需的最小交换次数是多少?哪一组在哪一端并不重要

例如:

[0,1,0,1]=[0,0,1,1]1掉期

[1,1,1,1,0,1,0]=[1,1,1,1,1,0,0]1掉期

[1,0,1,0,0,0,1]==[1,1,1,0,0,0,0,0]6次互换

请注意,这与此处提出的问题不同:

我没有对数组进行排序,我只是尝试将所有0和所有1组合在一起,而不管哪一个在哪一端

我真的不知道从哪里开始。有人能帮我吗?

使用冒泡排序的简单方法,需要O(n2),如下所示:

public class MainClass {

    public static void main(String[] args) {
        int[] arr = new int[]{1, 0, 0, 0, 0, 0, 0, 1, 0};
        int minSwaps = minimumSwaps(arr);
        System.out.println("Minimum swaps required: " + minSwaps);
    }

    public static int minimumSwaps(int[] array) {
        int[] arr1 = array.clone(), arr2 = array.clone();
        int swapsForRight = 0, swapsForLeft = 0;

        boolean sorted = false;

        while (!sorted) {
            sorted = true;
            for (int i = 0; i < arr1.length - 1; i++) {
                if (arr1[i + 1] < arr1[i]) {
                    int temp = arr1[i + 1];
                    arr1[i + 1] = arr1[i];
                    arr1[i] = temp;
                    sorted = false;
                    swapsForRight++;
                }
            }
        }
            
        sorted = false;
        while (!sorted) {
            sorted = true;
            for (int i = 0; i > arr2.length - 1; i++) {
                if (arr2[i + 1] < arr2[i]) {
                    int temp = arr2[i + 1];
                    arr2[i + 1] = arr2[i];
                    arr2[i] = temp;
                    sorted = false;
                    swapsForLeft++;
                }
            }
        }
        return swapsForLeft > swapsForRight ? swapsForRight : swapsForLeft;
    }
}
public类MainClass{
公共静态void main(字符串[]args){
int[]arr=newint[]{1,0,0,0,0,0,0,1,0};
int minSwaps=最小互换(arr);
System.out.println(“所需最低掉期:“+minSwaps”);
}
公共静态int最小交换(int[]数组){
int[]arr1=array.clone(),arr2=array.clone();
int swapsForRight=0,swapsForLeft=0;
布尔排序=假;
而(!排序){
排序=真;
for(int i=0;iarr2.length-1;i++){
if(arr2[i+1]swapsForRight?swapsForRight:swapsForLeft;
}
}

让我们关注零。每次交换都会将一个零移动到接近最终订单的一个位置。然后,我们可以通过找到置换零的数量,以及置换的严重程度来找到互换的数量

让我们先假设零在数组的开始处结束。我们将跟踪两件事:计数和位移,两者都初始化为零。每次我们找到一个1,我们就增加一个的计数。每次我们找到一个0,我们就增加位移的个数

然后我们朝另一个方向做。两种方法都是线性的,所以这是线性的

例如1010001

1: count_of_ones: 0 -> 1
0: displacement: 0 -> 1
1: count_of_ones: 1 -> 2
0: displacement: 1 -> 3
0: displacement: 3 -> 5
0: displacement: 5 -> 7
1: count_of_ones: 2 -> 3
这个方向的答案是最终位移,或7。从另一个方向走,我们得到5。最后的答案是5

事实上,最终位移之和(以全零开始与结束)将始终等于num_零*num_一。这将使工作减半(尽管它仍然是线性的)


从评论来看,似乎有些人不明白我的答案。下面是一个Ruby实现,让事情变得更清楚

def find_min_swaps(arr)
  count_of_ones = 0
  displacement = 0
  arr.each do |v|
    count_of_ones += 1 if v == 1
    displacement += count_of_ones if v == 0
  end

  count_of_zeroes = arr.length - count_of_ones
  reverse_displacement = count_of_ones * count_of_zeroes - displacement
  return [displacement, reverse_displacement].min
end

如果位移SUM0为所有零的(基于0的)索引之和,让
SUM1
为所有零的索引之和。每次交换
10
->
01
SUM0
下降一,而
SUM1
上升一。当您交换
01
->
10
时,它们会走另一条路

假设您有
N0
零和
N1
一。如果在数组的开头将零打包在一起,那么您将拥有
SUM0=N0*(N0-1)/2
。这是你能拥有的最小的
SUM0

由于单个相邻交换可以将
SUM0
精确减少1,因此需要精确的
SUM0-N0*(N0-1)/2
交换才能将前面的零组合在一起。类似地,需要
SUM1-N1*(N1-1)/2
交换才能将前面的交换打包在一起

你的答案是这些数字中较小的一个:
min(SUM0-N0*(N0-1)/2,SUM1-N1*(N1-1)/2)


这些值在线性时间内都很容易计算。

不确定如何计算互换。在你的第一个例子中,我可以通过交换元素1和2得到这个结果。@MarkRansom啊,是的,这是一个错误。编辑它!任何帮助都将不胜感激!与第二个示例相同,而且输出中似乎有一个额外的
1
。只需稍加调整即可尝试冒泡排序。@MarkRansom啊!我太粗心了!很抱歉这并不能回答问题。问题是计算所需掉期的数量,而不是对清单进行实际排序。现在OP改变了问题。。。秩序也不重要。。请稍等。您不需要对数组进行排序来计算交换的数量。@Dave您仍然需要对其进行排序,否则您将无法使用isSorted标志,您将永远无法确定您需要多少交换。@GiorgiTsiklauri请看我的答案。我按要求给出了代码。你可以不用排序就计算出所需的排序。对不起,你是怎么得到5的?还是7号?我不太清楚。。1) 最后的订单是什么?;2) 将零移动到哪里?正确的?左边3) 位移可能会有所不同,这取决于您对数组排序的顺序,相应地,位移的计数将产生不同的结果;4) 你为什么把方向定在零上?对不起,可能是我,但我只是很难理解你回答的逻辑。。甚至没有达到伪代码的级别。你们可能知道你们这里有什么,但解释肯定很糟糕