排列组合的题用回溯法和递归基本可以解决,总结一下。
46.全排列
手动模拟全排列的思想,就是固定一个数,然后让后面的继续做全排列,为了保证排列不一样,需要保证固定的数不一样。
这两份代码其实是一样的,不过上面那份用了引用,多了个交换的操作,都是每次固定不同的左端,然后继续递归进行全排列。
非递归算法参见https://blog.csdn.net/u014106644/article/details/83988102
47.全排列II
47比46多了个序列可重复的条件,意味着我们需要在46题基础上做个去重的操作,然后我们考虑在上面的两个模板上分别改一下。
第三种非递归写法,和上面那道题代码只有一处不一样
28行不一样
-
下一个排列
这道题的写法就是非重全排列的非递归写法中的一次寻找
60第k个排列
这道题有两种解法,一种就是把模拟下一次排列K次,比较慢,第二种采取数学方法做。
数学方法:待补
77组合
这道题可以做个剪枝,在18到19行,主要还是采取了回溯法。
39组合总和
这道题和上面那道题的不同之处在于限制条件不同,但思想还是回溯法进行挑选,还是要注意剪枝
40.组合总和 II
和上一道区别是元素可重复,但只能用一次。
这道题有两种解法:
sol1.转换成上面一道题,把重复的元素理解为单个元素可以重复取多次
sol2.通过比较相邻的点来进行判断是否重复选取
sol1明显好理解一点,在记录重复取的次数可以用unordered_map来保存,O(1)复杂度读取,分2种情况,如果可重复次数>1,那么仍然可以重复取这个数,如果==1,那么直接跳到下一个数。
sol2.如果前一个数没选取,但选取的数和前一个重复时,这种情况可以不要,也算一个剪枝,但不太好想。
216组合总和 III
377组合总和 Ⅳ
dfs复杂度太高了,t掉了,这道题没要求输出组合的结果,正确解法应该是dp,更确切的说记忆化dfs。
78子集
90子集 II
784字母大小写全排列
996正方形数组的数目
这道题就是47题全排列的改编版,进一步进行条件约束,注意边界。
排列是在原数组上两两交换,组合和子集是在容器里进行,子集是立刻输出,排列和组合是符合要求再输出
然后总而言之上面写的有点复杂,我们用标记数组的方式,用最简单的dfs的方式来写一遍,比较好理解
排列的题可以对path的位置做标记。。
46.code. https://leetcode-cn.com/submissions/detail/21611688/ (不重复排列) 输出字典序
47.code. https://leetcode-cn.com/submissions/detail/21612550/(重复排列)
组合的题
77.code.https://leetcode-cn.com/submissions/detail/21635210/ (不重复组合)
39.code. https://leetcode-cn.com/submissions/detail/18719647/ (重复组合总和)
40.code.https://leetcode-cn.com/submissions/detail/21638733/ (不重复组合总和)
216.code. https://leetcode-cn.com/submissions/detail/21639856/
377.code.https://leetcode-cn.com/submissions/detail/21641035/ (dp计数)
子集的题
78.code. https://leetcode-cn.com/submissions/detail/21641879/ (不重复子集)
90.code. (重复子集)