【代码随想录】d28-回溯算法-part04-python

1. 93. 复原 IP 地址

1.1题目及讲解

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。

  • 例如:“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “[email protected]” 是 无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 ‘.’ 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
题目链接/文章讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html
视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/

1.2代码实现

思路:
与回文子串的分割问题的处理是一样的,区别点在于,回文子串问题是需要判定path结果为回文字符串,本题需要判定结果满足有效IP

  • 范围有效:IP应该在[0,255]的闭区间内
  • 字符类型有效:只能是数字
  • 不能以0开头
  • 长度有效:IP地址长度应该为4
    【代码随想录】d28-回溯算法-part04-python_第1张图片
    代码实现:
s = "25525511135"
res = []
path = []


def back(startindex,s):
    if startindex == len(s) and len(path)==4:
        res.append('.'.join(path[:]))
        return
    for i in range(startindex,len(s)):
        tmp = s[startindex:i+1]
        # 1.判断字符串是否全部为数字;2.ip是否超出范围;3.判断字符串是否从0开始
        if tmp.isdigit() and  0 <= int(tmp) <= 255 and str(int(tmp)) == tmp:
            path.append(tmp)
        else:
            continue
        back(i + 1, s)
        path.pop()


back(0, s)
print(res)

2. 78. 子集

2.1题目及讲解

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

题目链接/文章讲解:https://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html
视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci

2.2代码实现

思路:

  • 子集问题与组合问题都可以抽象为一个树形结构,区别点在于子集问题需要收集树形结构的所有节点,而组合问题只需要收集树形结构的叶子节点
  • 实际代码收集结果时,操作是相同的,只是组合问题对结果有一定要求,例如取k个数字,和为target等,这样在最后收集结果时,就会把不符合条件的节点去掉
nums = [1,2,3]
path = []
res = []


def back(startindex,nums):
    res.append(path[:])
    if startindex == len(nums):  # 终止条件可以不写,因为当startIndex >= nums.size(),本层for循环本来也结束了
        return
    for i in range(startindex,len(nums)):
        path.append(nums[i])
        back(i+1,nums)
        path.pop()

back(0,nums)
print(res)

3. 90. 子集 II

3.1题目及讲解

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

题目链接/文章讲解:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html
视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J

3.2代码实现

思路:
78. 子集 的套路+40.组合总和II 的去重

  • 本题也可以不使用used数组来去重,因为递归的时候下一个startIndex是i+1而不是0。
  • 如果要是全排列的话,每次要从0开始遍历,为了跳过已入栈的元素,需要使用used。
##使用used数组去重
nums = [1,2,2]
nums.sort()
path = []
res = []
n = len(nums)
used = [False]* n


def back(startindex, nums):
    res.append(path[:])
    for i in range(startindex,n):
        if i > startindex and nums[i] == nums[i-1] and not used[i-1]:
            continue
        path.append(nums[i])
        used[i] = True
        back(i+1, nums)
        path.pop()
        used[i] = False
back(0,nums)
print(res)

不使用used数组去重

#不用used数组

nums = [1,2,2]
nums.sort()
path = []
res = []
n = len(nums)


def back(startindex, nums):
    res.append(path[:])
    for i in range(startindex,n):
        if i > startindex and nums[i] == nums[i-1]:
            continue
        path.append(nums[i])
        back(i+1, nums)
        path.pop()
back(0,nums)
print(res)

4.总结

  1. 如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
  2. 求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树
  3. 是否使用used数组来去重,取决于下一次递归时,是否从0开始,如果递归的时候下一个startIndex是i+1而不是0,那么就不需要使用used数组,
    • 如下图所示,树枝方向,进入下一层startindex取值为i+1,单层for循环本来就是从startindex,所以一定不满足i>startindex的条件
    • 树层方向,则在满足i > startindex and nums[i] == nums[i-1]时,就代表是重复的元素
      【代码随想录】d28-回溯算法-part04-python_第2张图片

如果要是全排列的话,每次要从0开始遍历,为了跳过已入栈的元素,需要使用used。

你可能感兴趣的:(算法,python)