按升序大小顺序的一组整数的k组合

时间:2010-04-08 11:43:56

标签: java algorithm

编程挑战:给定一组整数[1,2,3,4,5]我想在 Java中以升序大小顺序生成所有可能的k组合; e.g。

[1], [2], [3], [4], [5], [1, 2], [1, 3] ... [1, 2, 3, 4, 5]

生成一个生成所有组合然后对它们进行排序的递归解决方案相当容易,但我想有一种更有效的方法可以消除对额外排序的需求。

4 个答案:

答案 0 :(得分:9)

只需iterative deepening search

void comb(int... items) {
    Arrays.sort(items);
    for (int k = 1; k <= items.length; k++) {
        kcomb(items, 0, k, new int[k]);
    }
}
public void kcomb(int[] items, int n, int k, int[] arr) {
    if (k == 0) {
        System.out.println(Arrays.toString(arr));
    } else {
        for (int i = n; i <= items.length - k; i++) {
            arr[arr.length - k] = items[i];
            kcomb(items, i + 1, k - 1, arr);
        }
    }
}

然后打电话,说comb(10,20,30)。它会打印出来:

[10]
[20]
[30]
[10, 20]
[10, 30]
[20, 30]
[10, 20, 30]

答案 1 :(得分:3)

有两种方法可以解释“提升”要求。更宽松的解释是“在每个列表中,整数应按升序出现”。更严格的解释是“需要按顺序列出清单”。我想这就是你想要的那个,但我想出了一个简单的迭代方法来满足更宽松的要求。

对于n项,计算所有n位数。如果与项目对应的位在那里,则它在结果列表中。

public static void displaySubsets(List<Integer> sortedInts) {
    int n=sortedInts.size();
    long combinations = 1 << n;
    for (int setNumber=0; setNumber<combinations; setNumber++) {
      List<Integer> aResult = new ArrayList<Integer>();
      for (int digit=0; digit<n; digit++) {
        if ((setNumber & (1<<digit)) > 0) {
          aResult.add(sortedInts.get(digit));
        }
      }
      System.out.println(aResult.toString()+", ");
    }
  }

1,2,3,4,5的结果是: [], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3], [4], [1,4], [2,4], [1,2,4], [3,4], [1,3,4], [2,3,4], [1,2,3,4], [5], [1,5], [2,5], [1,2,5], [3,5], [1,3,5], [2,3,5], [1,2,3,5], [4,5], [1,4,5], [2,4,5], [1,2,4,5], [3,4,5], [1,3,4,5], [2,3,4,5], [1,2,3,4,5]

是的,我知道,我因不使用递归而失去了分数。

答案 2 :(得分:1)

我正在考虑更多,并意识到可以使用动态编程方法有效地完成它。下面是我生成的迭代解决方案,它使用Queue来保持状态(尽管可以使用Stack代替)。

我认为这比递归迭代深化搜索更有效,因为它不会涉及在生成期间重新访问现有状态;它会记住以前使用队列的状态,并使用这些状态生成连续的状态。

效果比较

Algorithm                    | 5 elems | 10 elems | 20 elems
--------------------------------------------------------------------------
Recursive (#recursions)      | 62      | 2046     | 2097150
Dynamic   (#loop iterations) | 32      | 1024     | 1048576

<强>代码

public class Test {
    private static class Pair {
        private final List<Integer> result;
        private final int index;

        private Pair(List<Integer> result, int index) {
            this.result = result;
            this.index = index;
        }

        public List<Integer> getResult() {
            return result;
        }

        public int getIndex() {
            return index;
        }
    }

    public static void main(String[] args) {
        List<Integer> items = Arrays.asList(1, 2, 3, 4, 5);
        foo(items);
    }

    private static void foo(List<Integer> items) {
        Queue<Pair> queue = new LinkedList<Pair>();
        queue.add(new Pair(Collections.<Integer>emptyList(), 0));

        while (!queue.isEmpty()) {
            Pair pair = queue.poll();

            System.err.println(pair.getResult());

            if (pair.getResult().size() < items.size()) {
                for (int i=pair.getIndex(); i<items.size(); ++i) {
                    List<Integer> copy = new LinkedList<Integer>(pair.getResult());
                    copy.add(items.get(i));
                    queue.add(new Pair(copy, i + 1));
                }
            }
        }
    }
}

答案 3 :(得分:0)

生成组合比排序花费的时间长,并且在给定n*log(n)排序时间的情况下排序100,000个数字并不需要很长时间。你是预先优化的。这很糟糕。