1.18二刷:画个树形图,真的会清楚很多。
今天又把前几天做的题目回顾了一下,感觉又清楚了一些。
组合总和问题:
组合问题取的是叶子结点,由于不同顺序的组合视为一个组合,因此需要一个startIndex下标,传入i+1作为参数,path中添加的就是当前i的下一个元素。因为元素是【1,9】,因此startIndex初始值为1,当前树枝遍历完k层后,startIndex变为最初的0,i++变为2,遍历i=2这个树枝。用来记录每个树层组合的开始下标。每次递归时i++,收集该树层的下一个元素。
组合总和III是求和为sum的组合,组合中不包含重复元素。i从startIndex开始,每次传递startIndex+1,因此列举出所有组合,进行判断和是否为k即可。每次回溯path[size-1]和sum值。
组合总和是求无重复元素的数组,但同一个 数字可以 无限制重复被选取的和为sum的组合,因此先对组合进行排序,首先每次都添加同一个元素,如果大于sum则break(回退到上一层的下一个元素),否则将元素加入path中,sum+=c[i],因为一个元素可以出现多次,因此回溯当前元素时传入i作为新的startIndex,【2,3,6,7】当当前树枝c[i]=2遍历结束后i++遍历c[i]=3这课树枝。遍历下一个数判断是否符合要求。
组合总和II是数组中包含重复元素,求何为sum的组合。不能包含相同的组合,但组合中元素可以相同。因此涉及到去重操作,只要同层前一个元素相等,当前元素遍历过的集合一定在前一个元素被遍历过了,因此需要对数组进行排序并定义一个used数组,组合不包含重复元素要求我们树层去重,树枝不去重。当used[i-1]为false且nums[i]==nums[i-1]时.代表同层前一个元素已经被遍历,若为true代表为同一个树枝上的元素,是一个集合里的元素,一个集合里可以包含重复元素因此不需要去重。,说明该树层前一个树枝已经把当前遍历的树枝遍历过一遍了,因此需要剪枝。
used数组树层去重图示
我终于看懂了!!!骄傲!!!
子集问题:
子集问题求的是树的每一个结点,每往path添加一个元素,都把path加入到结果集中,不需要判断条件。因此终止条件为path的大小==nums.length.
子集I不包含重复的元素,因此只需将遍历的元素加入path中,然后每次递归i+1作为新的startIndex即可,回溯path的最后一个元素。
子集II包含重复元素,不能包含重复子集说明要用used数组去重。因为每个子集中每个元素只能用一次(可以是数组中相同数字但不同下下标的元素),递归i+1作为下一层的树枝。
排列问题:
排列也是收集叶子结点。可以包含重复元组。因此不需要判断used[i-1]进行去重,但每次都需要判断used[i]是否被访问过。与组合最大的不同是每个排列中元素的不同顺序视为不同的组合,因此每次递归遍历时,i都从0开始,无需设置startIndex。并且需要定义used数组记录当前元素是否被访问过,每遍历一个元素将其used设置为1。每添加一个新元素都是从0到len遍历一遍,看还有没有没添加过的元素。当当前遍历的元素在组合中已经出现过时,即used[i]==true,则continue。若没有出现过则添加,并修改值为true。
排列II:不能包含重复元祖。因此去重同组合总和II。在全排列I的基础上加上判断条件i > 0 && nums[i] == nums[i - 1] && used[i-1]==false 即可去重。
·
used[i-1]==false:同层的前一个元祖已经被使用过。若不能包含有不同下标重复元素的重复元祖,则需要加上这步进行去重。
used[i-1]==true:当前遍历元素为当前层第一个遍历的元素。
used[i]==false:当前元素还未被使用。
used[i]==true:当前元素已经被使用。
需要通过used[i-1]去重的要对数组进行排序,判断当前元素是否和前一个元素值相同。