Bootstrap

力扣经典练习题之40,组合总和2

今天继续给大家分享一道力扣的做题心得今天这道题目是 40 ,组合总和

题目如下,题目链接:40. 组合总和 II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。 

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]


1,题目分析

此题目理解不难,如果做过组合这类的题目的话,此题的就是比一般的组合问题多了一个不能重复的要求。题目输入一个数组,和一个目标值,我们需要输出对应的可以使用这个数组里面的数组成对应目标值的每一个组合,并且不能重复,下面我们之间先来看解题代码

2,解题思路

class Solution {
    private List<List<Integer>> list;
    private List<Integer> stack;

   public Solution(){
    this.list = new ArrayList<>();
    this.stack = new ArrayList<>();
   }

    public List<List<Integer>> combinationSum2(int[] nums, int target) {
        Arrays.sort(nums);
        backtrack(nums,target,0);
        return list;
        
    }

    private void backtrack(int[] nums,int target,int startIndex){
      if(target == 0){
        list.add(new ArrayList<>(stack));
        return;
      }
        
      for(int i = startIndex;i < nums.length;i++){
        if(i > startIndex && nums[i] == nums[i - 1]) continue;
        if(target - nums[i] < 0) return;
        stack.add(nums[i]);
        backtrack(nums,target - nums[i],i + 1);
        stack.remove(stack.size()-1);
      }
    }
}

解题思路

  • 排序:首先对输入数组nums进行排序,这是为了方便后续的剪枝和去重操作。排序后,相同的元素会相邻,便于判断重复,同时也能在遍历时提前判断出后续元素是否会导致目标值超出范围。
  • 回溯法:采用回溯法来求解组合问题。回溯法是一种通过递归模拟所有可能的情况来寻找问题解的算法,适用于组合、排列等需要枚举多种情况的场景。
    • 递归终止条件:当目标值target减到0时,说明找到了一个满足条件的组合,将其加入结果列表list中,然后返回。
    • 递归遍历:从startIndex开始遍历数组nums,对于每个元素,先判断是否与前一个元素相同(i > startIndex && nums[i] == nums[i - 1]),若相同则跳过,这是为了去重,避免产生重复的组合。然后判断当前元素是否会导致目标值超出范围(target - nums[i] < 0),若超出则直接返回,因为数组已排序,后续元素只会更大,不可能满足条件。若当前元素可以加入组合,则将其加入栈stack中,递归调用backtrack函数,目标值减去当前元素,起始索引加1(backtrack(nums,target - nums[i],i + 1)),继续寻找下一个元素。递归返回后,需要将当前元素从栈中移除,以便回溯到上一步,尝试其他可能的组合。

数据结构使用

  • List<List<Integer>> list:用于存储所有满足条件的组合,是最终的输出结果。
  • List<Integer> stack:用于存储当前递归过程中形成的组合,相当于一个临时的栈结构,方便在递归过程中添加和移除元素,以模拟不同的组合情况。
  • int[] nums:输入数组,存储了题目给定的候选数字。
  • int target:目标值,需要找到所有候选数字的组合,使得这些数字的和等于目标值。

代码细节

  • 构造函数:在Solution类的构造函数中初始化了liststack,这样可以避免在每次调用combinationSum2方法时都重新创建这两个列表,提高代码的复用性。
  • 剪枝操作:在递归遍历过程中,通过判断target - nums[i] < 0来进行剪枝,当目标值减去当前元素小于0时,直接返回,不再继续递归,减少了不必要的计算,提高了算法效率。
  • 去重操作:通过判断i > startIndex && nums[i] == nums[i - 1]来去重,当当前元素与前一个元素相同且不是本轮递归的起始元素时,跳过当前元素,避免产生重复的组合,这是解决组合问题中常见的去重技巧。

总结

        此题我采用了经典的回溯法来求解组合总和问题,并通过排序、剪枝和去重等操作来优化算法,思路清晰,代码简洁,可以高效地找到所有满足条件的组合。数据结构的使用也比较合理,list用于存储最终结果,stack用于模拟递归过程中的组合情况,numstarget则是题目给定的输入参数。

3,总结

        感谢大家的阅读,希望这篇解题心得能为大家带来一些收获,我们共同进步!大家的点赞就是我的动力谢谢大家,还有什么更优解或者问题欢迎大家在评论区讨论分享!

;