Given an array of 0 and 1, find minimum no. of swaps to bring all 1s together (only adjacent swaps allowed)

前端 未结 4 599
生来不讨喜
生来不讨喜 2020-12-19 16:52

If given an array of 1\'s and 0\'s, what\'s good algorithm to show the minimum number of adjacent swaps needed to group all of the 1\'s together. The 1\'s don\'t need to be

相关标签:
4条回答
  • 2020-12-19 17:27

    Approach : This can be done by finding number of zeroes to the right side of every 1 and add them. In order to sort the array every one always has to perform a swap operation with every zero on its right side.

    So the total number of swap operations for a particular 1 in array is the number of zeroes on its right hand side. Find the number of zeroes on right side for every one i.e. the number of swaps and add them all to obtain the total number of swaps.

    // Java code to find minimum number of swaps to sort a binary array

    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)); 
        } 
    } 
    
    0 讨论(0)
  • 2020-12-19 17:28

    UPDATED:

    The algorithm determines center by just getting an array of all indices of 1's. The center of that array will always hold the center index. Much faster.

    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);
    

    Here's a fiddle to see it in action:

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

    This was a fun one. Thanks for the question.

    0 讨论(0)
  • 2020-12-19 17:31

    Here is a simple, but not very clever algorithm that will perform an exhaustive search for any input in the range [0, 255].

    • Input:
      • binary string
    • Output:
      • optimal number of steps
      • number of optimal solutions
      • one detailed example

    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>

    0 讨论(0)
  • 2020-12-19 17:39

    Hi, firstly I would like to suggest that the minimum number of adjacent swaps would be 2 for your given example instead of 3. As just swap index 0 with index 2. So 1 swap from left and 1 swap from right.

    Here is my way to find minimum of swaps to bring the array in consecutive 1's form -

    Step 1 : First find the centre index for maximum number of consecutive 1's Step 2 : Parse the left side of array to swap it and count the number of swap in a efficient manner(Do not swap unnecessarily) Step 3 : Do the same for the right side array Step 4 : Plus the counts of both side.

    Please have a look at my java program based on same strategy :

    `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);
    }
    

    } `

    I am not very sure about performance. But as per my knowledge it should not be inefficient. If anyone finds any performance issue please do let me know :)

    0 讨论(0)
提交回复
热议问题