北川广海の梦

北川广海の梦

笔记:全排列和组合的小细节区别

233
2020-05-03

全排列问题

给出一组数,输出这个数组中所有的数字组合。
不同的顺序,视作不同的结果。

组合问题

给出一组数,包含n个数字,输出其中k个数字的所有组合。

细节

这两个问题其实就非常像高中的排列组合,A和C的区别。
一个是有序,一个是无序的。在编程的时候需要特别注意。其差别主要体现在做选择的时候。

在全排列问题中,我们只需要关心路径是否重复,每次我们进行的选择,都不能包含重复的元素。
例如下面的写法:

	for (int i = 0; i < nums.length; i++) {
        // 排除不合法的选择
        if (track.contains(nums[i]))
            continue;
        // 做选择
        track.add(nums[i]);
        // 进入下一层决策树
        backtrack(nums, track);
        // 取消选择
        track.removeLast();
    }

我们就通过判断track路径中是否有了来判断是否重复路径。

而在组合问题中,我们就需要使所有元素都不和其他组合重复。
可以通过遍历的小技巧来做到:

	public void backtrack(int first, LinkedList<Integer> curr) {
            //结束条件
            if (curr.size() == k)
                output.add(new LinkedList(curr));

            for (int i = first; i < n + 1; ++i) {
                //添加进路径
                curr.add(i);
                //对于需要遍历的数,以下一个为起点,就能保证前面的元素不再重复
                backtrack(i + 1, curr);
                // 撤销选择
                curr.removeLast();
            }
        }

这样遍历,就能保证路径始终是一个从前往后的顺序,不会包含前面重复的。也非常类似高中时候的组合问题的样子。