【问题标题】:Is there a method returns all possible combinations for n choose k?是否有一种方法可以返回 n 选择 k 的所有可能组合?
【发布时间】:2019-01-19 07:25:04
【问题描述】:

我正在寻找库函数,它返回 k 集中 n 子集的任意组合。例如,我有一个集合 {1,2,3,4,5},我需要包含在这个集合中的 3 个数字的任意组合。顺序无所谓。 所以这个函数应该返回:

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

我曾尝试自己写,但没有成功,我放弃了。它仅在我从任何一组中取 3 个数字时才有效。 也许有人知道这个问题的库函数。

【问题讨论】:

标签: java math combinations


【解决方案1】:

我不知道任何库函数,但您可以使用以下解决方案:

import java.io.PrintStream;
import java.util.*;

public class CombinationCalc<T> {
    private void getSubsets(List<T> input, int length, int index, Set<T> currentSet, List<Set<T>> solution) {
        if (currentSet.size() == length) {
            solution.add(new HashSet<>(currentSet));
            return;
        }
        if (index == input.size()) {
            return;
        }
        T x = input.get(index);
        currentSet.add(x);
        getSubsets(input, length, index + 1, currentSet, solution);
        currentSet.remove(x);
        getSubsets(input, length, index + 1, currentSet, solution);
    }

    public List<Set<T>> getSubsets(List<T> input, int length) {
        List<Set<T>> solution = new ArrayList<>();
        getSubsets(input, length, 0, new HashSet<>(), solution);
        return solution;
    }

    public void printSolution(List<Set<T>> solution, PrintStream ps) {
        Iterator<Set<T>> solutionIterator = solution.iterator();
        ps.print("[");
        if (!solutionIterator.hasNext()) {
            ps.print("]");
        }
        while (solutionIterator.hasNext()) {
            Set<T> solutionEntry = solutionIterator.next();
            Iterator<T> setEntry = solutionEntry.iterator();
            ps.print("[");
            if (!setEntry.hasNext()) {
                ps.print("]");
            }
            while (setEntry.hasNext()) {
                T entry = setEntry.next();
                ps.print(entry);
                if (setEntry.hasNext()) {
                    ps.print(", ");
                } else {
                    ps.print("]");
                }
            }
            if (solutionIterator.hasNext()) {
                ps.print(", ");
            } else {
                ps.print("]");
            }
        }
        ps.println();
    }


    public static void main(String[] args) {
        CombinationCalc<Integer> calc = new CombinationCalc<>();
        List<Integer> input = Arrays.asList(1, 2, 3, 4, 5);
        List<Set<Integer>> solution = calc.getSubsets(input, 3);

        calc.printSolution(solution, System.out);
    }
}

它基于amit'ssolution

【讨论】:

    【解决方案2】:

    我在这里找到了递归解决方案: https://stackoverflow.com/a/16256122/10929764 但它只打印出组合。我试图修改它以将所有组合作为 ArrayList 返回,但它不起作用。 这是代码:

    public ArrayList<String[]> comb2(ArrayList<String>arr, int len, int startPosition, String[] result, ArrayList<String[]> allResults){
        if (len == 0){
            System.out.println(Arrays.toString(result));
            allResults.add(result);
            return allResults;
        }
        for (int i = startPosition; i <= arr.size()-len; i++){
            result[result.length - len] = arr.get(i);
            comb2(arr, len-1, i+1, result,allResults);
        }
        return allResults;
    }
    

    它正确打印出所有组合:

    [A, B, C] [A, B, D] [A, B, E] [A, C, D] [A, C, E] [A, D, E] [B, C, D] [B, C, E] [B, D, E] [C, D, E]

    但是当我打印出之前由 comb2 方法返回的 allResults 时:

    [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E] [C, D, E]

    【讨论】:

    【解决方案3】:

    这是一个使用流的简单而简短的解决方案:

    import java.util.Arrays;
    import java.util.Collections;
    import java.util.LinkedHashSet;
    import java.util.Set;
    
    import static java.util.stream.Collectors.toSet;
    
    public class MakeSubsets {
      static <T> Set<Set<T>> subsets(Set<T> set, int size) {
        if (size < 1) {
          return Collections.singleton(Collections.emptySet());
        }
        return set.stream()
              .flatMap(e -> subsets(remove(set, e), size - 1).stream().map(s -> add(s, e)))
              .collect(toSet());
      }
    
      static <T> Set<T> add(Set<T> set, T elem) {
        Set<T> newSet = new LinkedHashSet<>(set);
        newSet.add(elem);
        return newSet;
      }
    
      static <T> Set<T> remove(Set<T> set, T elem) {
        Set<T> newSet = new LinkedHashSet<>(set);
        newSet.remove(elem);
        return newSet;
      }
    
      public static void main(String[] args) {
        Set<Integer> set = new LinkedHashSet<>(Arrays.asList(1, 2, 3, 4, 5));
        System.out.println(subsets(set, 3));
      }
    }
    

    工作原理:subsets 方法生成给定大小的所有子集的集合。

    如果是size &lt; 1,它会返回一个集合,只包含空集合。

    否则对于给定集合的每个元素,它会生成一个没有此选定元素的新集合。然后它(递归地)生成具有这个较小集合的size - 1 元素的子集集合。然后它将所选元素添加到结果中的每个集合中。因此,结果中的所有集合都具有所需的大小。

    递归终止,因为在每个递归级别中,size 将减一,最终为 &lt; 1

    这里的假设是set.size() &gt;= sizesize &gt;= 0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-01
      • 1970-01-01
      • 2016-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多