代码随想录算法训练营第二十八天| LeetCode93. 复原 IP 地址、LeetCode78. 子集、LeetCode90. 子集 II

一、LeetCode93. 复原 IP 地址

        1:题目描述(93. 复原 IP 地址)

        有效 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 中的任何数字。你可以按 任何 顺序返回答案。

代码随想录算法训练营第二十八天| LeetCode93. 复原 IP 地址、LeetCode78. 子集、LeetCode90. 子集 II_第1张图片

        2:解题思路

class Solution:
    def __init__(self):
        self.res = []

    def restoreIpAddresses(self, s: str) -> List[str]:
        # 当字符串长度大于12时,怎么切割都不合法
        if len(s) > 12:
            return []
        # 当字符串长度小于等于12时,调用切割函数进行切割
        # 开始切割的起始位置为0,“.”的个数和为0
        self.division(s, 0, 0)
        return self.res
        
    def division(self, s, startindex, pointSum):
        # s表示字符串
        # startindex表示开始切割的位置
        # pointSum表示“.”的个数,当“.”个数为3时,字符串就全部被切割了
        if pointSum == 3:
            # 当“.”的个数等于3时,已经将字符串切割为4段了
            # 校验一下最后一段的字符串是否合法
            if self.is_valid(s, startindex, len(s)):
                # 合法,就将用“.”分割后的字符串加入到res中
                self.res.append(s)
                return 
        for i in range(startindex, len(s)):
            # 判断切割的字符串是否合法
            if self.is_valid(s, startindex, i+1):
                # 合法,切割字符串,加“.”
                s = s[:i+1] + "." + s[i+1:]
                # "."个数加1
                pointSum += 1
                # 调用递归,startindex为什么是i+2,因为添加了“.”,多了一个字符,整体往后移动了一个字符
                self.division(s, i+2, pointSum)
                # 回溯,为什么是i+2,因为添加了“.”,多了一个字符,整体往后移动了一个字符
                s = s[:i+1] + s[i+2:]
                pointSum -= 1
            else:
                break
            
    def is_valid(self, s, startindex, endindex):
        # 不符合要求的三种情况          
        if startindex >= endindex:
            # 当切割字符串的开始位置大于结束位置,直接返回False
            return False
        if s[startindex] == "0" and startindex != endindex-1:
            # 当切割两位以上,开头字符为0,不是合法的字符串,返回False
            return False
        if not 0 <= int(s[startindex:endindex]) <= 255:
            # 当切割的字符串的值不在0到255的范围内,不是合法的字符串,返回False
            return False
        return True

二、LeetCode78. 子集

        1:题目描述(78. 子集)

        给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

        解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

代码随想录算法训练营第二十八天| LeetCode93. 复原 IP 地址、LeetCode78. 子集、LeetCode90. 子集 II_第2张图片

        2:解题思路

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []             # 存放每个符合要求的子集
        def subset(nums, startindex):
            res.append(path[:])            # 将path加入res中
            if startindex == len(nums):
                # 当开始遍历的位置等于nums的长度时,返回上层
                return 
            for i in range(startindex, len(nums)):
                path.append(nums[i])
                subset(nums, i+1)
                # 回溯
                path.pop()
        subset(nums, 0)
        return res

三、LeetCode90. 子集 II

        1:题目描述(90. 子集 II)

        给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

        解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

代码随想录算法训练营第二十八天| LeetCode93. 复原 IP 地址、LeetCode78. 子集、LeetCode90. 子集 II_第3张图片

        2:解题思路

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        res = []
        path = []
        # used用来标记nums中对应下标的元素是否使用过,0为:没使用过,1为:已使用过
        used = [0] * len(nums)     
        # 先对nums进行排序        
        nums = sorted(nums)
        def subsets(nums, startindex, used):
            res.append(path[:])
            if startindex == len(nums):
                return
            for i in range(startindex, len(nums)):
                # 当i>0,前一个元素与当前元素的值相等,并且前一个元素没有被使用过
                # 说明改元素包含的组合已经在前一个元素中出现过,所以不用继续向下一层遍历了,直接进入下一次循环
                if i > 0 and nums[i-1] == nums[i] and used[i-1] == 0:
                    continue
                # 将当前元素加入到path中
                path.append(nums[i]) 
                # 将当前元素的下标在used中对应下标的元素值修改为1,表示这个元素被使用了
                used[i] = 1
                # 递归调用,进入下一层
                subsets(nums, i+1, used)
                # 回溯
                path.pop()
                # 需要把当前元素下标在used中对应下标的元素值修改为0,表示这个元素没有被使用
                used[i] = 0
        subsets(nums, 0, used)
        return res

你可能感兴趣的:(算法训练营(LeetCode),leetcode,算法,python,回溯算法)