在《代码随想录》中针对leetcode40:组合总和2提出了“树层重复”和“树枝重复”,通过used数组进行两种重复的去重操作
书中提到:
在candidates[i]和candidate[i-1]相同的情况下:
如果used[i-1]==true,则说明同一树枝使用过candidate[i-1],此时for循环跳过则为树枝去重
如果used[i-1]==false,则说明同一树层使用过candidate[i-1],此时for循环跳过则为树层去重
本题需要的去重操作为树层去重
上图这个案例,候选数组为cand[1,1,1,1,2],结点1要从候选数组中取出一个数字,如果取出cand[0],则跳转至结点2,此时used[0]被赋值为true
如果取出cand[1],则跳转到结点3,此时used[1]被赋值为true,满足:candidate[1]==candidate[0]且used[0]==false,所以结点3会被删除,为什么结点3会被删除呢?核心的原因在于结点2将把结点3所有的情况覆盖掉:
结点3包含的所有情况是:在组合[1]的基础上,在[1,1,2]中进行其余元素的选取
而结点2包含的所有情况是:在组合[1]的基础上,在[1,1,1,2]中进行其余元素的选取,又可以分为两大类情况:2.1:将选取[1,1,1,2]的第一个元素1 2.2:将不选取[1,1,1,2]的第一个元素1,即从剩下的[1,1,2]中选取
可以发现结点3包含的所有情况和结点2包含的子集情况(2.2)完全等价,所以完全可以把结点3删除
其余情况也是类似,总之,树层去重的本质就是候选数组中有若干个相同元素时,只能保留选取了这些相同元素的第一个元素的结点,而那些没有选取这些元素的第一个元素反而选取了这些元素的其它元素的结点应该被删除掉。例如此时候选数组有[1,1,1,2,2,3],本来可以有6个分支,但只能保留第一个、第四个和第六个分支,其它分支由于和前面的分支的子分支情况等价需要被删除掉