// 回溯算法伪代码
function backtracking(参数) {
if (终⽌条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
// 回溯求子集
function backtracking(nums, startIndex, path, result) {
result.push(path); // 收集⼦集,要放在终⽌添加的上⾯,否则会漏掉⾃⼰
if (startIndex >= nums.length) { // 终⽌条件可以不加
return;
}
for (let i = startIndex; i < nums.length; i++) {
path.push(nums[i]);
backtracking(nums, i + 1, [...path], result);
path.pop();
}
}
function subsets(nums) {
result = [];
path = [];
backtracking(nums, 0, path, result);
return result;
}
// 复原IP地址
给定⼀个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间⽤
'.' 分隔。
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和
"192.168@1.1" 是 ⽆效的 IP 地址。
// 判断字符串s在左闭⼜闭区间[start, end]所组成的数字是否合法
function isValid(s, start, end) {
if (start > end) {
return false;
}
if (s[start] == '0' && start != end) { // 0开头的数字不合法
return false;
}
let num = 0;
for (let i = start; i <= end; i++) {
if (s[i] > '9' || s[i] < '0') { // 遇到⾮数字字符不合法
return false;
}
num = num * 10 + (s[i] - '0');
if (num > 255) { // 如果⼤于255了不合法
return false;
}
}
return true;
}
function backtracking(s, startIndex, pointNum,result) {
if (pointNum == 3) { // 逗点数量为3时,分隔结束
// 判断第四段⼦字符串是否合法,如果合法就放进result中
if (isValid(s, startIndex, s.length - 1)) {
result.push(s);
}
return;
}
for (let i = startIndex; i < s.length; i++) {
if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的⼦串是否合法
s = s.slice(0, i + 1) + '.' + s.slice(i + 1); // 在i的后⾯插⼊⼀个逗点
pointNum++;
backtracking(s, i + 2, pointNum,result); // 插⼊逗点之后下⼀个⼦串的起始位置为i + 2
pointNum--; // 回溯
s = s.slice(0, i + 1) + s.slice(i + 2); // 回溯删掉逗点
} else break; // 不合法,直接结束本层循环
}
}
function restoreIpAddresses(s) {
let result = [];
if (s.length > 12) return result; // 算是剪枝了
backtracking(s, 0, 0,result);
return result;
}
console.log(restoreIpAddresses("25525511135"))
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int
startIndex, vector<bool>& used) {
if (sum == target) {
result.push_back(path);
return;
}
for (int i = startIndex; i < candidates.size() && sum + candidates[i]
<= target; i++) {
// used[i - 1] == true,说明同⼀树⽀candidates[i - 1]使⽤过
// used[i - 1] == false,说明同⼀树层candidates[i - 1]使⽤过
// 要对同⼀树层使⽤过的元素进⾏跳过
if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] ==
false) {
continue;
}
sum += candidates[i];
path.push_back(candidates[i]);
used[i] = true;
backtracking(candidates, target, sum, i + 1, used); // 和39.组合总和
的区别1,这⾥是i+1,每个数字在每个组合中只能使⽤⼀次
used[i] = false;
sum -= candidates[i];
path.pop_back();
}