Skip to content

Commit

Permalink
algorithm 回溯算法(子集和)文档撰写
Browse files Browse the repository at this point in the history
  • Loading branch information
wangtunan committed Mar 19, 2024
1 parent c8c6c80 commit 9ca98f0
Showing 1 changed file with 93 additions and 0 deletions.
93 changes: 93 additions & 0 deletions docs/algorithm/base/backTracking/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,104 @@ export const permutationsHasEqualValue = (nums) => {
return res;
};
```

## 子集和问题

### 无相等元素情况
假设给定一个正整数`nums`和一个目标正整数`target`,请找出所有可能的组合,使得组合中的元素和等于`target`。假设给定的数组无重复元素,且每个元素可以被选择多次,且不区分子集中元素的顺序。

例如:输入集合`[3, 4, 5]`和目标整数9,解为`[3, 3, 3]``[4, 5]`

![子集和问题-无相等元素](https://www.hello-algo.com/chapter_backtracking/subset_sum_problem.assets/subset_sum_i.png)

为了方便剪枝,我们需要对代码进行以下优化:
* 在开启搜索前,先将数组`nums`排序,在遍历时,当子集和超过`target`后直接结束循环。
* 设置开始遍历索引位置,避免出现重复的子集。

其代码实现如下:
```js
// 无重复元素子集和回溯算法
export const backTrackingNoEqualValue = (state, target, choices, start, res) => {
// 子集和等于目标值,记录子集
if(target === 0) {
res.push([...state]);
return;
}
// 遍历所有选择
// 剪枝一:从start开始遍历,避免出现重复自己
for (let i = start; i < choices.length; i++) {
const choice = choices[i];
// 剪枝二:如果子集和超过target,结束循环
if(target - choice < 0) {
break;
}
// 尝试:做出选择,更新target和start
state.push(choice);
// 下一次选择
backTrackingNoEqualValue(state, target - choice, choices, i, res);
// 回退:撤销选择
state.pop();
}
};
// 无重复元素子集和
export const subsetSumNoEqualValue = (nums, target) => {
const state = []; // 子集
const res = []; // 结果
const start = 0; // 起始遍历索引
nums.sort((a, b) => a - b); // 排序数组
backTrackingNoEqualValue(state, target, nums, start, res);
return res;
};
```

### 有相等元素情况
假设给定一个正整数数组`nums`和一个目标正整数`target`,请找出所有可能的组合,使得组合中的元素和等于`target`。假设给定的数字包含重复元素,每个元素只能被选取一次。

例如:输入数组`[4, 4, 5]`,目标数组`9`,相比于不重复数组,包含重复元素的输入数组最终得到的结果为`[4, 5]``[4, 5]`,如下图:

![子集和-有相等元素](https://www.hello-algo.com/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii_repeat.png)

为了解决以上问题,我们需要在剪枝的时候处理:因为已经是排序过后的数组,因此我们判断`choices[i]``choices[i + 1]`不相等时,直接跳过当前循环。

其实现代码如下:
```js
export const backTrackingHasEqualValue = (state, target, choices, start, res) => {
// 子集和等于目标值,记录子集
if(target === 0) {
res.push([...state]);
return;
}
// 遍历所有选择
// 剪枝一:从start开始遍历,避免出现重复自己
for (let i = start; i < choices.length; i++) {
const choice = choices[i];
// 剪枝二:如果子集和超过target,结束循环
if(target - choice < 0) {
break;
}
// 剪枝三:相同元素时,直接跳过
if(choice === choices[i - 1]) {
continue;
}
// 尝试:做出选择,更新target和start
state.push(choice);
// 下一次选择
backTrackingHasEqualValue(state, target - choice, choices, i, res);
// 回退:撤销选择
state.pop();
}
};

// 有重复元素字节和
export const subsetSumHasEqualValue = (nums, target) => {
const state = []; // 子集
const res = []; // 结果
const start = 0; // 起始遍历索引
nums.sort((a, b) => a - b); // 排序数组
backTrackingHasEqualValue(state, target, nums, start, res);
return res;
};
```

## N皇后问题

Expand Down

0 comments on commit 9ca98f0

Please sign in to comment.