【问题标题】:Generating all possible combinations with a dynamic size d?生成具有动态大小 d 的所有可能组合?
【发布时间】:2014-08-07 00:21:11
【问题描述】:

我想让这里的 d 动态化,即我希望能够在事先不知道 d 的值的情况下生成数组值的所有可能组合。

现在,我正在使用 if 子句,我只能支持 1 到 4 的 d。

这些是输入参数:d、max、min 和 sz。

if( d == 4 )
{
        for( double i = min ; i <= max ; i = i+ sz )
        {
            for( double j = min ; j <= max ; j = j + sz )
            {
                for( double h = min ; h<=max ; h = h + sz )
                {
                    for( double p = min ; p<=max ; p = p + sz )
                    {
                        double[] att = {i, j, h, p};
                    }
                }
            }
        }
}

if( d == 3 )
{
    for( double i = min ; i <= max ; i = i+ sz )
    {
        for( double j = min ; j <= max ; j = j + sz )
        {
            for( double h = min ; h<=max ; h = h + sz )
            {   
                double[] att = {i, j, h};
            }
        }
    }   
}

if( d == 2 )
{
    for( double i = min ; i <= max ; i = i+ sz )
    {
        for( double j = min ; j <= max ; j = j + sz )
        {
            double[] att = {i, j};
        }
    }   
}

if( d == 1 )
{
    for( double i = min ; i <= max ; i = i+ sz )
    {
        double[] att = {i, j};
    }   
}

如您所见,如果我之前不知道d的值,我将无法做到。

还有一件事,我不想使用任何模板或预定义的类,如 List 等。

【问题讨论】:

  • 您可以在 if 语句之外使用 for 循环来做到这一点。
  • 你返回的是什么,一个包含随机值的大小的数组?
  • 我只想打印出数组'att'。

标签: java arrays


【解决方案1】:

递归是你的朋友。对预定义类的限制使代码有点难看,但它的功能应该是一样的。这在复杂性方面也非常糟糕(您在递归时会产生很多额外的对象),但如果您真的想要可变数量的嵌套循环,这就是要走的路。

private static void makeAtt(double min, double max, double sz, int depth, double[] vals){
    //Guard against bad depth
    if (depth < 0) return;
    if (depth == 0){
        System.out.print("{"); 
        for(double d : vals){
            System.out.print(d + " ");
        }
        System.out.print("}\n\n");
    }
    else{
        for(double i = min; i < max; i += sz){
            double[] newVals = new double[vals.length + 1];
            for(int z = 0; z < vals.length; z++) newVals[z] = vals[z];
            newVals[vals.length] = i;
            makeAtt(min, max, sz, depth - 1, newVals);
        }
    }
}

这是一个运行示例:

public static void main(String[] args){
  makeAtt(0, 3, 1, 3, new double[0]);
}

输出:

{0.0 0.0 0.0 }

{0.0 0.0 1.0 }

{0.0 0.0 2.0 }

{0.0 1.0 0.0 }

{0.0 1.0 1.0 }

{0.0 1.0 2.0 }

{0.0 2.0 0.0 }

{0.0 2.0 1.0 }

{0.0 2.0 2.0 }

{1.0 0.0 0.0 }

{1.0 0.0 1.0 }

{1.0 0.0 2.0 }

{1.0 1.0 0.0 }

{1.0 1.0 1.0 }

{1.0 1.0 2.0 }

{1.0 2.0 0.0 }

{1.0 2.0 1.0 }

{1.0 2.0 2.0 }

{2.0 0.0 0.0 }

{2.0 0.0 1.0 }

{2.0 0.0 2.0 }

{2.0 1.0 0.0 }

{2.0 1.0 1.0 }

{2.0 1.0 2.0 }

{2.0 2.0 0.0 }

{2.0 2.0 1.0 }

{2.0 2.0 2.0 }


有一点需要注意;我的代码和您的原始答案实际上都会生成所有可能的排列,而不是组合。如果你想要组合,你应该让每个数字在递增之前从前一个数字开始,而不是从最小值开始。由于递归的设置方式,您所要做的就是将递归调用更改为:

makeAtt(i, max, sz, depth - 1, newVals);

【讨论】:

  • 代码没有打印出正确的输出。我尝试将深度用作 d,并将 vale[] 初始化为零数组,但我得到的只是最后一个元素更改的数组。
  • vale 应该被初始化为一个长度为 0 的数组;元素附加到它上面。它似乎对我有用,我将使用一些示例输出来编辑我的答案。
  • 感谢您澄清输入 val[]。
【解决方案2】:

你会喜欢这个的。我自己为此苦苦挣扎,经过几个小时的头痛后设计了以下算法:

// nCr
public static long c(int n, int r) {
    long result = 1;
    for (int i = 1; i <= r; i++) {
        result *= n - (r - i);
        result /= i;
    }
    return result;
}

public static int[] getCombo(int n, int r, long k) {
    int[] result = new int[r];
    int cur = 1;
    long sum = 0;
    while (r > 0) {
        long tot = c(n - cur, r - 1);
        if (sum + tot <= k) {
            sum += tot;
            cur += 1;
        } else {
            result[result.length - r] = cur;
            cur += 1;
            r--;
        }
    }
    return result;
}

public static void main(String[] args) {

    for (int i = 0; i < c(10,3); i++) {
        int[] res = getCombo(10, 3, i);
        System.out.print(i + " : ");
        for (int j : res) System.out.print(j+" ");
        System.out.println();
    }
}

要使用它,只需从 0 开始指定元素的数量 (n) 和要从中选择的数量 (r) 以及想要的组合 (k)。这样您就可以遍历组合而不将它们全部保存在一个数组中。

例如,getCombo(10, 3, 0) 将给出 [1, 2, 3]。当然从 10 中选择 3 有 120 种可能性,所以 getCombo(10, 3, 119) 会给你 [8,9,10]

该算法基于计算以 1 开头然后是 2 等的各种数字组合。

【讨论】:

    【解决方案3】:

    我的代码与@Mshnik 的代码非常相似,但没有复制,问题是您是否可以在一个地方处理组合或必须一次返回所有组合...

    http://ideone.com/uCUVfk

    import java.util.*;
    import java.lang.*;
    import java.io.*;
    
    class Combinations
    {
    
        static void printCombinations( int K, int[] A ) {
            for ( int i = 0; i < A.length; ++i ) {
                printCombinations( K, A, i, new int[K], 0 );
            }
        }
    
        static void printCombinations( int K, int[] A, int from, int[] curr,  int idx ) {
            if ( from >= A.length ) return;
            if ( idx == K ) { System.out.println( Arrays.toString(curr) ); return; }
            curr[idx] = A[from];
            for ( int i = from + 1; i < A.length; ++i ) {
                printCombinations( K, A, i, curr,  idx + 1 );
            }
        }
    
        public static void main (String[] args) throws java.lang.Exception
        {
            BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
            // K - elements in combination
            int K = Integer.parseInt( br.readLine() );
            // N - input array size
            int N = Integer.parseInt( br.readLine() );
            StringTokenizer tok = new StringTokenizer( br.readLine() );
            int[] A = new int[N];
            for ( int i = 0; i < N; ++i ) {
                A[i] = Integer.parseInt( tok.nextToken() );
            }
            //System.out.println( "DEBUG: " + Arrays.toString( A ) );
            printCombinations( K, A );
        }
    }
    

    可以完全组合的地方是

    if ( idx == K ) { System.out.println( Arrays.toString(curr) ); return; }
    

    我只是打印它,你可以将它传递给一些方法并处理它......

    【讨论】:

      猜你喜欢
      • 2013-06-19
      • 2016-01-07
      • 2022-08-22
      • 2022-01-18
      • 2019-05-16
      相关资源
      最近更新 更多