Leetcode 93.复原 IP 地址

题目:93.复原 IP 地址

初始思路

代码

  1. var restoreIpAddresses = function (s) {
  2. const res = [], path = [];
  3. backtracking(0, 0)
  4. return res;
  5. function backtracking (i) {
  6. const len = path.length;
  7. if (len > 4) return;
  8. if (len === 4 && i === s.length) {
  9. res.push(path.join("."));
  10. return;
  11. }
  12. for (let j = i; j < s.length; j++) {
  13. const str = s.slice(i, j + 1);
  14. if (str.length > 3 || +str > 255) break;
  15. if (str.length > 1 && str[0] === "0") break;
  16. path.push(str);
  17. backtracking(j + 1);
  18. path.pop()
  19. }
  20. }
  21. };

感想

  1. 需要判断到底截了几段,还要判断是否有前导0和数字范围。
    image.png

Leetcode 78.子集

题目:78.子集

初始思路

这题原来写过一次,感觉像模板题。

代码

  1. var subsets = function (nums) {
  2. const res = []
  3. const path = []
  4. const backtracking = (startIndex) => {
  5. // 收集子集,要放在终止添加的上面,否则会漏掉自己
  6. res.push([...path])
  7. if (startIndex >= nums.length) return
  8. for (let i = startIndex; i < nums.length; i++) {
  9. path.push(nums[i])
  10. backtracking(i + 1)
  11. path.pop()
  12. }
  13. }
  14. backtracking(0)
  15. return res
  16. };

感想

  1. 如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!
  2. 求排列问题的时候,就要从0开始,因为集合是有序的,{1, 2} 和{2, 1}是两个集合。
  3. image.png

Leetcode 90.子集 II

题目:90.子集 II

初始思路

跟上一题不同的是,这题有重复元素,而且不能有重复的子集。在昨天的40题中也进行了去重操作。

代码

  1. var subsetsWithDup = function (nums) {
  2. let res = []
  3. let path = []
  4. nums.sort((a, b) => a - b)
  5. const backtracking = (startIndex) => {
  6. // 收集子集,要放在终止添加的上面,否则会漏掉自己
  7. res.push([...path])
  8. if (startIndex >= nums.length) return
  9. for (let i = startIndex; i < nums.length; i++) {
  10. if (i > startIndex && nums[i] === nums[i - 1]) continue
  11. path.push(nums[i])
  12. backtracking(i + 1)
  13. path.pop()
  14. }
  15. }
  16. backtracking(0)
  17. return res
  18. };

感想

  1. 从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!
    image.png