回溯算法-组合总和 II

217 阅读2分钟

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

Hope is a good thing, maybe the best of things. And no good thing ever dies.

前言

回溯算法是对树形或者图形结构执行一次深度优先遍历,实际上类似枚举的搜索尝试过程,在遍历的过程中寻找问题的解。

深度优先遍历有个特点:当发现已不满足求解条件时,就返回,尝试别的路径。此时对象类型变量就需要重置成为和之前一样,称为「状态重置」

题目

给定一个数组 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]
]

示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

分析

本题 candidates 中的每个数字在每个组合中只能使用一次。 本题数组 candidates 的元素是有重复的,而 组合总和 是无重复元素的数组 candidates

难点在于:集合(数组candidates)有重复元素,但还不能有重复的组合

解题

const combinationSum2 = (candidates, target) => {
  candidates.sort((a,b) => a - b ); // 升序排序
  const res = [];

  const dfs = (start, temp, sum) => { // start是索引 当前选择范围的第一个
    if (sum >= target) {        // 不继续选了
      if (sum == target) {      // 满足条件,加入解集
        res.push(temp.slice()); // temp是引用,所指向的内存后续还要操作,所以拷贝一份
      }
      return;                   // 结束当前递归
    }
    for (let i = start; i < candidates.length; i++) {             // 枚举出当前的选择
      if (i - 1 >= start && candidates[i - 1] == candidates[i]) { // 当前选项和左邻选项一样,跳过
        continue;
      }
      temp.push(candidates[i]);              // 作出选择
      dfs(i + 1, temp, sum + candidates[i]); // 基于该选择,继续选择,递归
      temp.pop();               // 上面的递归结束,撤销选择,回到选择前的状态,切入另一分支
    }
  };

  dfs(0, [], 0);
  return res;
};

附:leetcode-cn.com/problems/co…

结语

如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。

文章如有错误之处,希望在评论区指正🙏🙏

欢迎关注我的微信公众号,一起交流技术,微信搜索 🔍 :「 五十年以后