【问题标题】:Given an array of 0 and 1, find minimum no. of swaps to bring all 1s together (only adjacent swaps allowed)给定一个由 0 和 1 组成的数组,找到最小值。将所有 1 组合在一起的交换次数(仅允许相邻交换)
【发布时间】:2016-08-03 16:12:02
【问题描述】:

如果给定一个 1 和 0 的数组,有什么好的算法可以显示将所有 1 组合在一起所需的最小相邻交换数。 1 不需要在数组中的任何特定位置分组。只需将它们分组在任何提供最少相邻交换数量的位置即可。

例如,如果数组看起来像这样......

1,0,0,1,1,0,1

...相邻交换的最小数量为 3,因为您将以索引 4 为中心并执行以下交换:

  1. 交换索引 0 和 1,结果是: 0,1,0,1,1,0,1

  2. 交换索引 1 和 2,结果是: 0,0,1,1,1,0,1

  3. 交换索引 5 和 6,结果是: 0,0,1,1,1,1,0

谁有一个很好的算法来找到任何 1 和 0 数组的最小相邻交换数?

【问题讨论】:

  • 这个其实有点意思。我以为您只是在排序,但您的目标是对所有 1 进行分组,而不管索引位置如何。嗯。
  • 问题标题说明了交换的最小数量(不是部分移位),在示例中为 2(交换索引 0,2 | 交换索引 5,6)。也许你的意思是相邻的互换?
  • @rcgldr,是的,看这个例子,不过,我认为 OP 要求相邻的交换。
  • 答案将涉及找到一个“人口中心”将 1 分组到,然后进行计算以确定分组所需的步数。很有趣。
  • 接近选民:虽然这个问题没有很好地提出,但 OP 的要求既不清楚也不太宽泛。请重新考虑。

标签: arrays algorithm sorting


【解决方案1】:

更新:

该算法仅通过获取所有索引为 1 的数组来确定中心。该数组的中心将始终保存中心索引。更快。

oneIndices = array of indices of all 1's in the input
middleOfOnesIndices = round(oneIndices.length/2)-1    // index to the center index
minimumSwaps = 0
foreach index i of oneIndices
    minimumSwaps += aboluteValue(oneIndices[middleOfOneIndices]-oneIndices[i])-absoluteValue(middleOfOneIndices-i);

这是一个实际操作的小提琴:

https://jsfiddle.net/3pmwrk0d/6/

这很有趣。感谢您的提问。

【讨论】:

  • 肯定有O(n)解,我稍后检查我的算法并贴出来。
  • 一个方便的中心如此易于计算绝对不是那么明显。那么每个 1 的交换次数就是到该中心的距离减去它们之间的 1 的数量。非常好。
  • 非常好的算法。该算法背后的数学定理是什么?
【解决方案2】:

嗨,首先我想建议您给定的示例中相邻交换的最小数量为 2 而不是 3。就像将索引 0 与索引 2 交换一样。所以从左侧交换 1 个,从左侧交换 1 个对。

这是我找到最小交换以将数组带入连续 1 形式的方法 -

第 1 步:首先找到最大连续 1 数的中心索引 第2步:解析数组的左侧以交换它并以有效的方式计算交换次数(不要不必要地交换) 第 3 步:对右侧数组执行相同操作 第 4 步:加上双方的计数。

请看一下我基于相同策略的java程序:

`public class MinimumSwap 
{
//function to find consecutive number index
public static int[] getMaxConsecutiveIndex(List<Integer> array)
{
    int desiredIndex = -1;
    int count = 0;
    int dupDesiredIndex = -1;
    int dupCount = 0;

    int i = 0;
    while(i < array.size())
    {
        if(array.get(i) == 0)
        {
            //pass duplcateIndex value to desiredIndex if count is more
            if(dupCount > count)
            {
                desiredIndex = dupDesiredIndex;
                count = dupCount;
            }
            dupDesiredIndex = -1;
            dupCount = 0;
        }
        else 
        {
            if(dupDesiredIndex == -1) 
            {
                dupDesiredIndex = i;
                dupCount = 1;
            }
            else
            {
                dupCount++;
            }
        }
        i++;
    }
    return new int[]{desiredIndex,count};
}

public static int swapCount(List<Integer> array,int startIndex, int      endIndex, boolean side)
{
    // side == false means 0 at the left
    // side == true means 1 at the left
    System.out.println("startIndex  "+startIndex+"  endIndex  "+endIndex+" side "+side);
    int swapCount = 0; 
    if(side == false)
    {
        while(startIndex <= endIndex)
        {
            if(array.get(endIndex) == 0) // swap from the end only if it is 0
            {
                //check for first 1 from left to swap
                while(array.get(startIndex) == 0 && (startIndex != endIndex))
                    startIndex++;

                if(array.get(startIndex) == 1)  
                {
                    // now swap
                    int temp = array.get(startIndex);
                    array.set(startIndex, array.get(endIndex));
                    array.set(endIndex,temp);
                    swapCount++;
                    endIndex--;
                }
            }
            endIndex--;
        }
    }
    else
    {
        while(startIndex <= endIndex)
        {
            if(array.get(startIndex) == 0) // swap from the starting only if it is 0
            {
                //check for first 1 from right to swap
                while(array.get(endIndex) == 0 && (startIndex != endIndex))
                    endIndex--;
                if(array.get(endIndex) == 1)    
                {
                    // now swap
                    int temp = array.get(startIndex);
                    array.set(startIndex, array.get(endIndex));
                    array.set(endIndex,temp);
                    swapCount++;
                    startIndex++;
                }
            }
            startIndex++;
        }
    }
    return swapCount;
}

public static void main(String...strings)
{
    List<Integer> arr = new ArrayList<Integer>();
    int temp[] = {0,1,1,0,0,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1};
    //int temp[] = {1,0,0,1,1,0,1};
    for(int i=0; i<temp.length; i++)
        arr.add(temp[i]);


    int centerIndex = getMaxConsecutiveIndex(arr)[0];
    int consequtivecount = getMaxConsecutiveIndex(arr)[1];
    System.out.println("centerIndex "+centerIndex+"  consequtivecount "+consequtivecount);
    int swapCountLeft = swapCount(arr,0, centerIndex-1, false);
    int swapCountRight = swapCount(arr,centerIndex+consequtivecount, arr.size()-1, true);
    System.out.println("total swap count "+swapCountLeft+" :: "+swapCountRight);
    System.out.println("array after swapping "+arr);
}

} `

我不太确定性能。但据我所知,它不应该是低效的。如果有人发现任何性能问题,请告诉我:)

【讨论】:

  • 请重新阅读帖子。他要求相邻交换的最小数量。
  • 是的,你是对的,他要求相邻的交换。我没有正确理解这个问题。在这种情况下,交换的第二个功能需要更改为计算双方相邻交换的最小数量。让我更改该功能并重新发布。
  • 请问您可以编辑您的帖子以反映评论吗?
【解决方案3】:

方法: 这可以通过在每个 1 的右侧找到多个零并将它们相加来完成。为了对数组进行排序,每个人总是必须在其右侧每个零执行交换操作。

因此数组中特定 1 的交换操作总数是其右侧的零数。找到每个右侧的零的数量,即交换的数量,并将它们全部相加以获得交换的总数。

// 查找最小交换次数以对二进制数组进行排序的 Java 代码

class MinimumNumberOfSwapsNeeded { 

    static int findMinSwaps(int arr[], int n) 
    { 
        // Array to store count of zeroes 
        int noOfZeroes[] = new int[n]; 
        int i, count = 0; 

        // Count number of zeroes 
        // on right side of every one. 
        noOfZeroes[n - 1] = 1 - arr[n - 1]; 
        for (i = n - 2; i >= 0; i--)  
        { 
            noOfZeroes[i] = noOfZeroes[i + 1]; 
            if (arr[i] == 0) 
                noOfZeroes[i]++; 
        } 

        // Count total number of swaps by adding number 
        // of zeroes on right side of every one. 
        for (i = 0; i < n; i++)  
        { 
            if (arr[i] == 1) 
                count += noOfZeroes[i]; 
        } 
        return count; 
    }       
    // Driver Code 
    public static void main(String args[]) 
    { 
        int ar[] = { 0, 0, 1, 0, 1, 0, 1, 1 }; 
        System.out.println(findMinSwaps(ar, ar.length)); 
    } 
} 

【讨论】:

    【解决方案4】:

    ** 将 0 和 1 的数组分组,使得最小交换可以在 O(2*n) ~ O(n) 复杂度内计算。**

    package com.segregate.array;    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ArraySegregation {
        public static void main(String[] args) {
            List<Integer> arr = new ArrayList<>();
            /*
             * 
             * List -> low high [1 1 0 0 1 0] -> [ 000111] or [111000]
             * 
             * 1 1 0 0 1 0 -> 000111
             */
            arr.add(0);
            arr.add(0);
            arr.add(0);
            arr.add(1);
            arr.add(1);
            arr.add(0);
            arr.add(1);
            arr.add(0);
            arr.add(0);
            List<Integer> arr1 = new ArrayList<>(arr);
    
            int low = 0, high = arr.size() - 1;
            int counter1 = 0, counter2 = 0;
            // case for swaps such that all 0 in the left side.
            while (low < high) {
                switch (arr.get(low)) {
                case 0:
                    while (arr.get(low) == 0)
                        low++;
                    break;
                case 1:
                    while (arr.get(high) == 1)
                        high--;
                    swap(low, high, arr);
                    counter1++;
                    high--;
                    low++;
                    break;
                }
    
            }
            // case for swaps such that all 0 in the right side.
            /*
             * [1 1 0 0 1 0] -> 11 1 0 0 0
             * 
             * 
             */
            low=0;high = arr1.size() - 1;
            while (low < high) {
                switch (arr1.get(low)) {
                case 0:
                    while (arr1.get(high) == 0)
                        high--;
                    swap(low, high, arr1);
                    counter2++;
                    high--;
                    low++;
                    break;
                case 1:
                    while (arr1.get(low) == 1)
                        low++;
                    break;
                }
    
            }
            
            int count = (counter1 > counter2) ? counter2 : counter1;
            System.out.println(count);
        }
    
        private static void swap(int low, int high, List<Integer> arr) {
            int temp1 = 0;
            temp1 = arr.get(low);// 1
            arr.remove(low);
            arr.add(low, arr.get(high-1));
            arr.remove(high-1);
            arr.add(high, temp1);
        }
    }
    

    【讨论】:

      【解决方案5】:

      这是一个简单但不是很聪明的算法,它将对 [0, 255] 范围内的任何输入执行穷举搜索。

      • 输入:
        • 二进制字符串
      • 输出:
        • 最佳步数
        • 最优解数
        • 一个详细的例子

      var transition = [],
          isSolution = [];
      
      function init() {
        var msk = [ 3, 6, 12, 24, 48, 96, 192 ],
            i, j, n, x, cnt, lsb, msb, sz = [];
      
        for(i = 0; i < 0x100; i++) {
          for(n = cnt = msb = 0, lsb = 8; n < 8; n++) {
            if(i & (1 << n)) {
              cnt++;
              lsb = Math.min(lsb, n);
              msb = Math.max(msb, n);
            }
          }
          sz[i] = msb - lsb;
          isSolution[i] = (sz[i] == cnt - 1);
        }
        for(i = 0; i < 0x100; i++) {
          for(j = 0, transition[i] = []; j < 0x100; j++) {
            x = i ^ j;
            if(msk.indexOf(x) != -1 && (x & i) != x && (x & j) != x && sz[j] <= sz[i]) {
              transition[i].push(j);
            }
          }
        }
      }
      
      function solve() {
        var x = parseInt(document.getElementById('bin').value, 2),
            path = [ x ],
            list = [],
            i, min, sol = [], res = [];
      
        recurse(x, path, list);
      
        for(i in list) {
          if(min === undefined || list[i].length <= min) {
            min = list[i].length;
            (sol[min] = (sol[min] || [])).push(list[i]);
          }
        }
        console.log('Optimal length: ' + (min - 1) + ' step(s)');
        console.log('Number of optimal solutions: ' + sol[min].length);
        console.log('Example:');
      
        for(i in sol[min][0]) {
          res.push(('0000000' + sol[min][0][i].toString(2)).substr(-8, 8));
        }
        console.log(res.join(' -> '));
      }
      
      function recurse(x, path, list) {
        if(isSolution[x]) {
          list.push(path);
          return;
        }
        for(i in transition[x]) {
          if(path.indexOf(y = transition[x][i]) == -1) {
            recurse(y, path.slice().concat(y), list);
          }
        }
      }
      
      init();
      <input id="bin" maxlength="8" placeholder="enter binary string">
      <button onclick="solve()">solve</button>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-03
        • 2019-11-14
        • 2011-06-06
        • 1970-01-01
        • 1970-01-01
        • 2020-04-21
        • 2020-12-10
        • 1970-01-01
        相关资源
        最近更新 更多