基本流程:
注:for循环是横向遍历N叉树,递归是纵向遍历N叉树
for循环起点是start还是0?
在递归过程中,下一层是否可以选择集合里的所有元素
可选范围是(start,len)还是(0,len)
当通过一个集合求组合(或分割或子集),需要start,防止重复;
当通过多个集合求组合(或分割或子集),不需要start,因为各个集合都不同不会相互影响;
如果是排列问题的话,就不需要start,因为每到新的一列都需要重新使用之前使用的元素;
如果有start,什么时候递归时i加1?
看下一层中,当前元素是否可重复使用
下一层的可选范围:(i,len)还是(i+1.len)
当一个集合中每个元素只能使用一次时,i + 1;
当一个集合中每个元素可以重复使用时,不用加1;
小结:
设置for的起点,和递归设置i的原理是一样的,用于决定下一层的可选范围
不同的是,如果for设置的起点为0,说明下一层的可选范围是整个集合
递归中i不加1,说明下一层的可选范围是从i(包括i)开始(i可重复使用)
关于去重:
树层(同一层)去重:(当集合中有重复的元素,但是结果要求不能有重复的组合,则需要去重)
有两种方法:如果需要保存原集合的顺序,则采用方法一,如果不需要考虑顺序,采用方法二
方法一:used[i] == false,说明同一树层元素 i 使用过
例题:力扣491. 递增子序列(JavaScript)_csD_Dscnnnnnnn的博客-CSDN博客
491.递增子序列 :给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例:
- 输入: [4, 6, 7, 7]
- 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
集合中有重复的元素(两个7),但是结果数组中,不允许有相同的组合,所以需要去重
查找递增序列,必然是不可以打乱集合的排序,所以采用方法一去重
use的下标是nums[i]的值
use初始化的位置:记录同层的元素是否使用过(不涉及递归),所以在进入每层的遍历前,就需要初始化
方法二:排序去重
例题:力扣90. 子集 II(JavaScript)_csD_Dscnnnnnnn的博客-CSDN博客
90.子集II :给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
- 输入: [1,2,2]
- 输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
排序:
nums.sort((a,b)=>a-b)
如果当前元素,与前一个元素相等,则结束此次循环
for(let i=index;i<len;i++){
if(i>index&&nums[i]==nums[i-1]){
continue
}
p.push(nums[i])
dd(i+1)
p.pop()
}