有效计算所有排列

时间:2014-04-03 14:04:55

标签: java performance algorithm processing-efficiency

受到一个含糊不清的问题的启发,我感到很难解决对它的更难解释,具体如下:

如何最有效地计算包含 n 零(0位)的所有可能的整数值(32位值)?例如,给定 n = 7 ,包含 7 零的不同整数值的数量为:

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

具有恰好7个零的示例整数值将是:

11111111000000011111111111111111

如果您想自己解决问题,请避免阅读我的答案。否则,请评估我的答案,改进它或发布更好,更有效的答案。

2 个答案:

答案 0 :(得分:1)

我的算法的想法如下:

  1. 创建一个整数值,在右侧(最低有效位)使用与函数permut()相同的零。
  2. 开始向左移动最左边的零点。
  3. 将移动的零点右侧的所有位视为目标值,并将相同的算法应用于缩短值。
  4. 该算法有两个重要特征:

    • 是递归的
    • 它需要与计算值一样多的计算

    这里算法为Java代码:

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

    如果您对算法行为正常感到好奇,请使用修改后的main()方法尝试以下检查方法:

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

答案 1 :(得分:0)

假设您要枚举实际数字,您可以简单地创建一个大小为32且具有n 0的字符数组,然后置换数组

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

它很慢,因为有m!排列,其中m是数组的大小。我将大小设置为5以加快速度。