// 回溯算法伪代码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, intstartIndex, 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(); }