From 0d6a3a751373f0c5a1ffeac11efbd125d2cbc5d9 Mon Sep 17 00:00:00 2001 From: Sainnhe Park Date: Thu, 2 Feb 2023 11:33:45 +0800 Subject: [PATCH] s0040 --- include/s0040_combination_sum_ii.hpp | 14 ++++++++++ notes/src/combinations.md | 27 ++++++++++++++++++- src/s0040_combination_sum_ii.cpp | 39 ++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 include/s0040_combination_sum_ii.hpp create mode 100644 src/s0040_combination_sum_ii.cpp diff --git a/include/s0040_combination_sum_ii.hpp b/include/s0040_combination_sum_ii.hpp new file mode 100644 index 0000000..35212aa --- /dev/null +++ b/include/s0040_combination_sum_ii.hpp @@ -0,0 +1,14 @@ +#ifndef S0040_COMBINATION_SUM_II_HPP +#define S0040_COMBINATION_SUM_II_HPP + +#include +#include + +using namespace std; + +class S0040 { + public: + vector> combinationSum2(vector& candidates, int target); +}; + +#endif diff --git a/notes/src/combinations.md b/notes/src/combinations.md index c51c7a3..7d8a0e9 100644 --- a/notes/src/combinations.md +++ b/notes/src/combinations.md @@ -69,6 +69,31 @@ void combineDFS(int n, int k, int begin, vector &path, } ``` +## [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) + ## [39. 组合总和](https://leetcode.cn/problems/combination-sum/) -## [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) +## [40. 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/) + +最难的一个组合总和,因为 `candidates` 有重复元素,而要求最终结果不能重复。 + +e.g. 1 + +```text +Input: candidates = [10,1,2,7,6,1,5], target = 8 +Output: +[ +[1,1,6], +[1,2,5], +[1,7], +[2,6] +] +``` + +如果你只是单纯地在 s0039 的基础上在下一次递归中将 `startIndex` 设为 `i + 1` 那么最终结果就会出现两个 `[1, 2, 5]`。 + +如果你直接排除 `candidates[i] == candidates[i - 1]` 的情形,那么最终结果就没有 `[1, 1, 6]`。 + +正确的逻辑应该是如果 `candidates[i] == candidates[i - 1]` 且 `candidates[i - 1]` 使用过,则剪枝。 + +怎么判断 `candidates[i - 1]` 是否使用过呢?我们创建一个 `vector used` 用来记录每个元素是否使用过。 diff --git a/src/s0040_combination_sum_ii.cpp b/src/s0040_combination_sum_ii.cpp new file mode 100644 index 0000000..604cb5b --- /dev/null +++ b/src/s0040_combination_sum_ii.cpp @@ -0,0 +1,39 @@ +#include "s0040_combination_sum_ii.hpp" + +void combinationSum2DFS(vector &candidates, int target, int startIndex, + vector &path, int sum, vector &used, + vector> &result) { + // 结束条件:总和等于 target 。不存在总和大于 target 的情况,因为已经被剪枝了 + if (sum == target) { + result.push_back(path); + return; + } + + // 开始迭代 + int size = candidates.size(); + for (int i = startIndex; i < size; ++i) { + // 剪枝,当现在节点的 sum 已经超过了 target,就没必要继续迭代了 + if (sum + candidates[i] > target) break; + // 剪枝,要对同一树层使用过的元素进行跳过 + if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) + continue; + path.push_back(candidates[i]); + used[i] = true; + combinationSum2DFS(candidates, target, i + 1, path, sum + candidates[i], + used, result); + used[i] = false; + path.pop_back(); + } +} + +vector> S0040::combinationSum2(vector &candidates, + int target) { + // 对 candidates 进行升序排序,这是为了进行剪枝 + sort(candidates.begin(), candidates.end()); + // 初始化 + vector path{}; + vector> result{}; + vector used(candidates.size(), false); + combinationSum2DFS(candidates, target, 0, path, 0, used, result); + return result; +}