1

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.

cic
  • 7,310
  • 3
  • 23
  • 35
Harmlezz
  • 7,972
  • 27
  • 35
  • This is not about the power set of a set. – G. Bach Apr 03 '14 at 14:11
  • You might find this C++ solution useful: http://stackoverflow.com/questions/14713584/find-n-th-set-of-a-powerset/14717440#14717440 – rici Apr 03 '14 at 14:43
  • http://programmers.stackexchange.com/a/67087/44026 – leventov Apr 03 '14 at 15:16
  • I corrected the title. I am in search of all permutations and not of the power set. My fault, sorry. – Harmlezz Apr 03 '14 at 16:18
  • Actually, you are trying to enumerate all [combinations](http://en.wikipedia.org/wiki/Combination) n zeroes and 32-n ones, not all [permutations](http://en.wikipedia.org/wiki/Permutations) of a bit sequence. That is, your description does not match your terminology. – meriton May 16 '15 at 13:36

2 Answers2

1

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;
}
Harmlezz
  • 7,972
  • 27
  • 35
0

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.

turingcomplete
  • 2,128
  • 3
  • 16
  • 25