Update notes for s0040

This commit is contained in:
Sainnhe Park 2023-02-03 12:14:39 +08:00
parent ca4fe2293d
commit fe6a4ec73f
2 changed files with 32 additions and 2 deletions

View File

@ -96,4 +96,34 @@ Output:
正确的逻辑应该是如果 `candidates[i] == candidates[i - 1]``candidates[i - 1]` 使用过,则剪枝。 正确的逻辑应该是如果 `candidates[i] == candidates[i - 1]``candidates[i - 1]` 使用过,则剪枝。
怎么判断 `candidates[i - 1]` 是否使用过呢?我们创建一个 `vector<bool> used` 用来记录每个元素是否使用过。 ![demo](https://paste.sainnhe.dev/DMfz.png)
那么我们现在要来定义一下什么叫“使用过”。这张图里面有两种“使用过”,第一种使用过是“在树枝上使用过”,第二种使用过是“在数层上使用过”。
第一种“使用过”显然是合法的,我们允许元素在一条树枝上重复出现。而第二种“使用过”是不合法的,生成的结果重复了。
因此我们只需要对第二种“使用过”进行剪枝,而保留第一种“使用过”。
怎么做呢?我们创建一个 `vector<bool> used` 用来记录元素是否在树枝上出现过,初始化为 `false`
```cpp
used[i] = true;
combinationSum2DFS(candidates, target, i + 1, path, sum + candidates[i],
used, result);
used[i] = false;
```
那么 `used[i - 1] == true` 说明 `candidates[i - 1]` 在树枝上出现过,我们需要保留这种情况,不剪枝。
```cpp
// 剪枝,但保留树枝重复的情况
if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false)
continue;
```
另外需要注意一点,为了进行剪枝,我们需要对 `candidates` 进行排序:
```cpp
// 对 candidates 进行升序排序,这是为了进行剪枝
sort(candidates.begin(), candidates.end());
```

View File

@ -14,7 +14,7 @@ void combinationSum2DFS(vector<int> &candidates, int target, int startIndex,
for (int i = startIndex; i < size; ++i) { for (int i = startIndex; i < size; ++i) {
// 剪枝,当现在节点的 sum 已经超过了 target就没必要继续迭代了 // 剪枝,当现在节点的 sum 已经超过了 target就没必要继续迭代了
if (sum + candidates[i] > target) break; if (sum + candidates[i] > target) break;
// 剪枝,要对同一树层使用过的元素进行跳过 // 剪枝,但保留树枝重复的情况
if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false)
continue; continue;
path.push_back(candidates[i]); path.push_back(candidates[i]);