用于创建具有重复的给定数量(N)的M个自然数的组合的算法

时间:2016-03-08 13:07:57

标签: java algorithm

我正在寻找一种算法,该算法可以打印M个自然数的所有组合,这些组合可以重复创建给定的数字(N)。

让我们说我们的java函数是:public static String [] foo(6,3)其中6是N,3是M. 答案应该是:

0,0,6
0,1,5
0,2,4
0,3,3
1,1,4
1,2,3
2,2,2

and foo(7,4):
0,0,0,7
0,0,1,6
0,0,2,5
0,0,3,4
0,1,1,5
0,1,2,4
0,1,3,3
1,1,1,4
1,1,2,3
1,2,2,2 (if im not wrong...)

提前谢谢!

2 个答案:

答案 0 :(得分:1)

这是一种递归方法,观察你开始需要M个数字,这可以分解成一个更简单的M-1数问题,直到M = 1.

public class RecursiveCombinations {

    public static void main(String[] args) {
        solve(4,7,0,"");
    }

private static void solve(int M, int remainingValue, int previousLevel, String solutionSoFar) {
    if (M == 1) {
        System.out.println(solutionSoFar+remainingValue);
        return;
    }
    for (int i = previousLevel; i<=remainingValue/M; i++) {
        String s = solutionSoFar+i+",";
        solve(M-1, remainingValue-i, i, s);
    }
}

创建输出:

0,0,0,7
0,0,1,6
0,0,2,5
0,0,3,4
0,1,1,5
0,1,2,4
0,1,3,3
0,2,2,3
1,1,1,4
1,1,2,3
1,2,2,2

答案 1 :(得分:0)

最简单的方法是生成长度为M的数组以及最多N个数字的所有可能组合,并测试每一个数字以获得正确的结果。
非常蛮力,但会工作。你可以从那里建立起来(消除加倍的结果......)

您可能还想查看Backtracking

这可能是这样的:

import java.util.LinkedList;

public class Tests 
{

    public static void main(String[] aargh)
    {
        LinkedList<int[]> arr = numarrays(7,4);
        for(int i = 0; i< arr.size();i++)
        {
            int[] curr = arr.get(i);
            for(int j = 0; j < curr.length;j++)
            {
                System.out.print(curr[j]+" ,"); 
            }
            System.out.println();
        }
    }

    public static LinkedList<int[]> numarrays(int result, int depth)
    {
        LinkedList<int[]> retVal = new LinkedList<int[]>();

        int[][] val = new int[1][];

        while(next(result,depth,val))
        {
            if(reject(result, val[0])) continue;
            if(!accept(result, val[0])) continue;   
            retVal.add(val[0].clone());
        }

        return retVal;
    }

    private static boolean reject(int max, int[] in) 
    {
        int sum = 0;
        for(int i = 0; i< in.length; i++)
        {
            sum += in[i];
            if(sum > max) return true;
        }

        return false;
    }

    private static boolean accept(int target, int[] in) 
    {
        int sum = 0;
        for(int i = 0; i< in.length; i++)
        {
            sum += in[i];
        }

        if(sum == target) return true;

        return false;
    }

    private static boolean next(int max, int depth, int[][] val) 
    {
        if(val[0] == null)
        {
            val[0] = new int[depth];
            return true;
        }

        return nextrec(max,val[0],0);
    }

    private static boolean nextrec(int max, int[] curr, int i) 
    {
        if(i>=curr.length) return false;

        if(nextrec(curr[i],curr,i+1)) return true;

        if(curr[i]< max)
        {
            curr[i]++;
            zerorec(curr,i+1);
            return true;
        }

        return false;
    }

    private static void zerorec(int[] curr, int i) 
    {
        if(i>=curr.length) return ;
        curr[i] = 0; 
        zerorec(curr,i+1);
    }
}