算法偶记:子集组合(给定一个元素个数为N的集合(其中元素互不相同),在其中选择M个元素组成子集,共有多少种选法。举例:输入[A,B,C] ,M=2,输出[[A,B],[A,C],[B,C]])

1.  给定一个元素个数为N的集合(其中元素互不相同),在其中选择M个元素组成子集,共有多少种选法。举例:输入[A,B,C] ,M=2,输出[[A,B],[A,C],[B,C]]

public static void main(String[] args) {
        System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 1));
        System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 2));
        System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 3));
        System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 4));
        System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 5));
        System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 6));
        System.out.println(method(Arrays.asList(1, 2, 3, 4, 5, 6, 7), 7));
    }

    public static List<List> method(List argsList, int m) {
        List result = new ArrayList<>();
        for (int i = 0; i < argsList.size(); i++) {
            List arg = new ArrayList<>();
            arg.add(argsList.get(i));
            if (m == 1) {
                // 如果只有1个数字的组合
                result.add(arg);
                continue;
            }
            // j是 第二位数的索引
            int j = i + 1;
            // count 是圈数
            int count = 0;
            // argsList.size() - j + 1 >= m  主要是判断后面的数字还需不需要循环
            // 例子:1 2 3 4 如果我是需要3个数的组合,那你的循环是不会到3的,因为3后面只有4,最多是2个数的组合,只会到2,2后面有3和4,才能符合3个数的组合
            while (argsList.size() - j + 1 >= m) {
                arg = new ArrayList<>();
                arg.add(argsList.get(i));
                int max = i;
                for (int l = 0; arg.size() < m - 1; l++) {
                    // 这里的作用主要是获取最后一位数之前的全部数
                    // 例子 1 2 3 4 5 , 4位数的组合, 我的想法是 先获取 1 2 3 公共的前缀,然后 遍历4和5
                    arg.add(argsList.get(j + l));
                    max = j + l;
                }
                // k 是最后一位数的索引
                int k = max + count + 1;
                while (arg.size() != m) {
                    // 这里就是为了遍历最后一个数字
                    arg.add(argsList.get(k++));
                }
                result.add(arg);
                if (k == argsList.size()) {
                    // 当k等于最后一位数时,说明 已经遍历完了,第二位数字需要跳到下一位,
                    // 例子 1 2 3 4 ,3位数组合,当k等于索引3的时候,说明 123, 124都遍历完了,需要跳到 13开头
                    j++;
                    count = 0;
                    if (m == 2) {
                        break;
                    }
                    continue;
                }
                // 圈数累加
                count++;
            }
        }
        return result;
    }

猜你喜欢

转载自blog.csdn.net/itjavaee/article/details/109327436
今日推荐