【问题标题】:Efficient computation of all permutations高效计算所有排列
【发布时间】:2014-04-03 14:04:54
【问题描述】:

受到一个模棱两可的问题的启发,我感到挑战解决更难的解释,如下所示:

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

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

正好有 7 个零的整数值示例如下:

11111111000000011111111111111111

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

【问题讨论】:

标签: java performance algorithm processing-efficiency


【解决方案1】:

我的算法思路如下:

  1. 创建一个整数值,其右边的零(最低有效位)与为函数 permut() 提供的一样多。
  2. 开始将最左边的零一点一点地向左移动。
  3. 将移动后的零右侧的所有位视为目标值,并将相同的算法应用于缩短值。

该算法有两个重要特点:

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

这里的算法是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;
}

【讨论】:

    【解决方案2】:

    假设您要枚举实际数字,您可以简单地创建一个大小为 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 以加快速度。

    【讨论】:

      猜你喜欢
      • 2019-08-04
      • 1970-01-01
      • 2011-01-06
      • 1970-01-01
      • 2016-08-05
      • 2019-11-05
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多