Harmlezz
Harmlezz

Reputation: 8068

Efficient computation of all permutations

Inspired by an ambiguously asked question, I felt challenged to solve the harder interpretation of it, which is as following:

How to compute most efficiently all possible integer values (32 bit values) containing exactly n zeros (0 digits)? For example, given n = 7, the number of different integer values containing exactly 7 zeros is:

32*31*30*29*28*27*26 / (1*2*3*4*5*6*7) = 3.365.856

An example integer value with exactly 7 zeros would be:

11111111000000011111111111111111

In case you like to solve the problem by yourself, avoid to read my answer. Otherwise evaluate my answer, improve it or post an even better, more efficient one.

Upvotes: 1

Views: 244

Answers (2)

Harmlezz
Harmlezz

Reputation: 8068

The idea of my algorithm is as following:

  1. Create an integer value with as many zeros at the right (least significant bits) as given to the function permut().
  2. Start to move the left most zero bit by bit to the left.
  3. Treat all the bits to the right of the moved zero as the target value an apply the same algorithm to the shorten value.

The algorithm has two important characteristics:

  • It is recursive
  • It requires as many computations as values to calculate

Here the algorithm as Java code:

public static void main(String[] args) {
    List<Integer> permutations = permut(7);
}

private static List<Integer> permut(int zeros) {
    List<Integer> permutations = new ArrayList<>();
    permut(zeros == 32 ? 0 : 0xFFFFFFFF << zeros, zeros, 31, permutations);
    return permutations;
}

/*
 * @param value
 *     for which to move the zero digit at bit position (zeros - 1)
 *     to the stopBit position
 * @param zeros
 *     number of 0 digits available at the right most bit positions
 *     of value
 * @param stopBit
 *     the left most bit position to move the zero digit at bit position
 *     (zeros - 1) to
 * @param values
 *     to add the newly calculated integer values to
 */
private static void power(int value, int zeros, int stopBit, List<Integer> values) {
    values.add(value);
    if (zeros == 0) return;
    int cleared = value | (1 << (zeros - 1));
    for (int bit = zeros - 1; bit < stopBit;) {
        power(cleared ^ (1 << ++bit), zeros - 1, bit - 1, values);
    }
}

If you are curious if the algorithm behaves correctly, try the following checking methods with the modified main() method:

public static void main(String[] args) {
    int zeros = 7;
    List<Integer> permutations = permut(zeros);
    System.out.println("Expected number of values:  " + combinations(zeros));
    System.out.println("Returned number of values:  " + permutations.size());
    System.out.println("Returned values are unique: " + (new HashSet<>(permutations).size() == permutations.size()));
    System.out.printf("All values contain %d zeros: %s\n", zeros, haveZeros(zeros, permutations));
}

private static long combinations(int zeros) {
    long p = 1;
    long q = 1;
    for (int count = 0; count < zeros;) {
        p *= (32 - count);
        q *= (++count);
    }
    return p / q;
}

private static boolean haveZeros(int zeros, List<Integer> values) {
    for (Integer value : values) {
        int count = 0;
        for (int bit = 1; bit != 0; bit = bit << 1) {
            if ((value & bit) == 0) count++;
        }
        if (count != zeros) {
            System.out.println(Integer.toBinaryString(value));
            return false;
        }
    }
    return true;
}

Upvotes: 1

turingcomplete
turingcomplete

Reputation: 2188

Assuming that you want to enumerate the actual numbers, you can simply create an array of chars of size 32 with exactly n 0, then permute the array

import java.io.*;
import java.util.*;

public class Solution
{

    static char [] arr;
    public static void main(String[]args)
    {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        arr = new char[5];
        for(int i = 0; i < arr.length; i++)
        {
            if(n > 0)
            {
                arr[i] = '0';
                n--;
            }
            else
                arr[i] = '1';
        }
        permute(0);
    }

    public static void permute(int i)
    {
        if(i >= arr.length)
        {
            System.out.println(arr);
            return;
        }

        int [] dups = new int[2];

        for(int j = i; j < arr.length; j++)
        {
            if(dups[arr[j]-'0'] == 1)
                continue;
            dups[arr[j]-'0'] = 1;
            char temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            permute(i+1);
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
}

It's slow because there are m! permutations where m is the size of the array. I set the size to be 5 to speed things up.

Upvotes: 0

Related Questions