1. // 回溯算法伪代码
    2. function backtracking(参数) {
    3. if (终⽌条件) {
    4. 存放结果;
    5. return;
    6. }
    7. for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) {
    8. 处理节点;
    9. backtracking(路径,选择列表); // 递归
    10. 回溯,撤销处理结果
    11. }
    12. }
    13. // 回溯求子集
    14. function backtracking(nums, startIndex, path, result) {
    15. result.push(path); // 收集⼦集,要放在终⽌添加的上⾯,否则会漏掉⾃⼰
    16. if (startIndex >= nums.length) { // 终⽌条件可以不加
    17. return;
    18. }
    19. for (let i = startIndex; i < nums.length; i++) {
    20. path.push(nums[i]);
    21. backtracking(nums, i + 1, [...path], result);
    22. path.pop();
    23. }
    24. }
    25. function subsets(nums) {
    26. result = [];
    27. path = [];
    28. backtracking(nums, 0, path, result);
    29. return result;
    30. }
    31. // 复原IP地址
    32. 给定⼀个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
    33. 有效的 IP 地址 正好由四个整数(每个整数位于 0 255 之间组成,且不能含有前导 0),整数之间⽤
    34. '.' 分隔。
    35. 例如:"0.1.2.201" "192.168.1.1" 有效的 IP 地址,但是 "0.011.255.245""192.168.1.312"
    36. "192.168@1.1" ⽆效的 IP 地址。
    37. // 判断字符串s在左闭⼜闭区间[start, end]所组成的数字是否合法
    38. function isValid(s, start, end) {
    39. if (start > end) {
    40. return false;
    41. }
    42. if (s[start] == '0' && start != end) { // 0开头的数字不合法
    43. return false;
    44. }
    45. let num = 0;
    46. for (let i = start; i <= end; i++) {
    47. if (s[i] > '9' || s[i] < '0') { // 遇到⾮数字字符不合法
    48. return false;
    49. }
    50. num = num * 10 + (s[i] - '0');
    51. if (num > 255) { // 如果⼤于255了不合法
    52. return false;
    53. }
    54. }
    55. return true;
    56. }
    57. function backtracking(s, startIndex, pointNum,result) {
    58. if (pointNum == 3) { // 逗点数量为3时,分隔结束
    59. // 判断第四段⼦字符串是否合法,如果合法就放进result中
    60. if (isValid(s, startIndex, s.length - 1)) {
    61. result.push(s);
    62. }
    63. return;
    64. }
    65. for (let i = startIndex; i < s.length; i++) {
    66. if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的⼦串是否合法
    67. s = s.slice(0, i + 1) + '.' + s.slice(i + 1); // 在i的后⾯插⼊⼀个逗点
    68. pointNum++;
    69. backtracking(s, i + 2, pointNum,result); // 插⼊逗点之后下⼀个⼦串的起始位置为i + 2
    70. pointNum--; // 回溯
    71. s = s.slice(0, i + 1) + s.slice(i + 2); // 回溯删掉逗点
    72. } else break; // 不合法,直接结束本层循环
    73. }
    74. }
    75. function restoreIpAddresses(s) {
    76. let result = [];
    77. if (s.length > 12) return result; // 算是剪枝了
    78. backtracking(s, 0, 0,result);
    79. return result;
    80. }
    81. console.log(restoreIpAddresses("25525511135"))
    82. class Solution {
    83. private:
    84. vector<vector<int>> result;
    85. vector<int> path;
    86. void backtracking(vector<int>& candidates, int target, int sum, int
    87. startIndex, vector<bool>& used) {
    88. if (sum == target) {
    89. result.push_back(path);
    90. return;
    91. }
    92. for (int i = startIndex; i < candidates.size() && sum + candidates[i]
    93. <= target; i++) {
    94. // used[i - 1] == true,说明同⼀树⽀candidates[i - 1]使⽤过
    95. // used[i - 1] == false,说明同⼀树层candidates[i - 1]使⽤过
    96. // 要对同⼀树层使⽤过的元素进⾏跳过
    97. if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] ==
    98. false) {
    99. continue;
    100. }
    101. sum += candidates[i];
    102. path.push_back(candidates[i]);
    103. used[i] = true;
    104. backtracking(candidates, target, sum, i + 1, used); // 和39.组合总和
    105. 的区别1,这⾥是i+1,每个数字在每个组合中只能使⽤⼀次
    106. used[i] = false;
    107. sum -= candidates[i];
    108. path.pop_back();
    109. }