代码随想录算法训练营第二十一天|93.复原IP地址、78.子集、90.子集II

写代码的第二十一天
回溯第三天,加油呀呀呀呀!!!

93.复原IP地址

思路

这个题也是一道切割问题,和昨天的回文串不同之处在于,回文串是可以一直切割一直到字符串结束,但是本题是找合法的IP地址,还是画个图。所以只能切三刀,切完需要判断三刀生成的四个字符串数字格式是否在0-255之间并且不以0开头,所以纵向的递归一共是三层分别是第一刀,第二刀和第三刀。
在这里插入图片描述
解决问题1:参数和返回值是什么?参数一定包含本题传入的字符串,并且还要有startindex代表每次切割的位置,以及用来判断切了几刀的pointnum这个参数是为了终止条件设置的;返回值这里也就是树中符合条件的路径,那么本题中用result存储符合条件的输出值。
解决问题2:终止条件是什么?本题中只能切三刀,所以我们要以这个作为终止条件,所以设置一个变量pointnum用来存储切了几刀,一旦等于3了那就证明可以结束了。上次的分割回文串的问题我们使用startindex作为终止条件是因为上次的结束条件是字符串的最后一位,也没限制切几刀,而是一直到最后,所以我们用的startindex表示每次切割的位置也完全可以到达字符串的最后位置,所以是可以用startindex作为终止条件的,但是本题中startindex只有三次,谁也不能确定这个第三次的位置究竟在哪,所以要在设置一个变量用来存储切了几次,其实也就是IP地址中的“.”。
解决问题3:单次回溯的逻辑是什么?横向用for循环,纵向用递归。横向for循环遍历整个字符串,纵向进行递归和回溯。如果切割出来的字符串的数字值大于255,或者不等于零但是首位字符为0,或者字符串中含有其他非正整数的字符,不符合条件。将出了这几种情况之外的字符串append。需要注意一定要把第四段加入进去!!!
正确代码:这个是别人的代码,我理解了一下写出来的。。。。。

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        result = []
        self.backtracking(s, 0, 0, "", result)
        return result

    def backtracking(self, s, start_index, point_num, current, result):
        if point_num == 3:
            if self.is_valid(s, start_index, len(s) - 1):  
                current += s[start_index:]  
                result.append(current)
            return

        for i in range(start_index, len(s)):
            if self.is_valid(s, start_index, i):  
                sub = s[start_index:i + 1]
                self.backtracking(s, i + 1, point_num + 1, current + sub + '.', result)
            else:
                break

    def is_valid(self, s, start, end):
        if start > end:
            return False
        if s[start] == '0' and start != end: 
            return False
        num = 0
        for i in range(start, end + 1):
            if not s[i].isdigit():  
                return False
            num = num * 10 + int(s[i])
            if num > 255:  
                return False
        return True

下面是我自己的思路我没改出来救命了。。。先留下,周末看看
错误第一版:解答错误,发现下面的结果中都是空,也就证明path里面没有值。每个ip地址的分块都是最多三位,一旦四位就超过255了,所以在for循环中不应该从startindex一直遍历到最后一位,而是最多三位,所以应该改为for i in range(startindex,min(startindex + 3, len(s))):。

class Solution:
    def __init__(self):
        self.path = []
        self.result = []
    def isvaild(self,s,start,end):
        if start > end:
            return False
        elif s == "":
            return False
        elif s[0] == "0":
            return False
        elif int(s) > 255 or int(s) < 0:
            return False
        return True
    def backtracing(self,s,startindex,pointnums):
        if pointnums == 3:
            if self.isvaild(s,startindex,len(s)-1):
                self.result.append('.'.join(self.path))
                return
        for i in range(startindex,len(s)):
            if self.isvaild(s,startindex,i+1):
                self.path.append(s[startindex:i+1])
                self.backtracing(s,i+1,pointnums+1)
                self.path.pop()

    def restoreIpAddresses(self, s: str) -> List[str]:
        self.backtracing(s,0,1)
        return self.result

错误第二版:输出结果没有最后两位数?????最后判断的第四块没进入path。

class Solution:
    def __init__(self):
        self.path = []
        self.result = []
    def isvaild(self,s,start,end):
        if start > end:
            return False
        elif s == "":
            return False
        elif s[0] == "0" and start != end:
            return False
        elif int(s[start:end+1]) > 255:
            return False
        return True
    def backtracing(self,s,startindex,pointnums):
        if pointnums == 4:
            if self.isvaild(s,startindex,len(s)-1):
                self.result.append('.'.join(self.path))
                return
        for i in range(startindex,min(startindex + 3, len(s))):
            if self.isvaild(s,startindex,i):
                self.path.append(s[startindex:i+1])
                self.backtracing(s,i+1,pointnums+1)
                self.path.pop()

    def restoreIpAddresses(self, s: str) -> List[str]:
        self.backtracing(s,0,1)
        return self.result

78.子集

思路

还是先画图,画个树出来。图中可以很清晰的知道我们要存储的最终结果是哪些,和之前组合的题很像是吧,但是区别在于组合的题我们要看的都是叶子结点的内容,而子集问题要看每一个结点的内容,除了跟结点。
在这里插入图片描述
解决问题1:参数和返回值?参数是传入的数组以及每次遍历开始的startinedex,也就是告诉我们下一次递归从哪里开始取;设置全局变量self.path以及self.result两个用来存储结果。
解决问题2:终止条件是什么?当数组中的全部数值都已经取完了,也就是startindex已经到最后了,startindex>=len(nums),的情况也就是到达了叶子结点了,此时终止。
解决问题3:单次回溯的逻辑是什么?横向for,纵向递归。横向的for指的是图中的取1,取2,取3这块。
注释:if终止条件大家可以看见其实在for循环中已经判断了,这个if其实写不写都行,因为本题要的是全部的结点值,不仅仅是叶子结点,所以不管是不是叶子结点的值都要append进result。
正确代码

class Solution:
    def __init__(self):
        self.path = []
        self.result = []
    def backtracing(self,nums,startindex):
        self.result.append(self.path.copy())
        if startindex >= len(nums):
            return
        for i in range(startindex,len(nums)):
            self.path.append(nums[i])
            self.backtracing(nums,i+1)
            self.path.pop()
    def subsets(self, nums: List[int]) -> List[List[int]]:
        self.backtracing(nums,0)
        return self.result

90.子集II

思路

又是似曾相识的题,先画图。
在这里插入图片描述
解决问题1:参数和返回值?参数是传入的数组以及每次遍历开始的startinedex,也就是告诉我们下一次递归从哪里开始取;设置全局变量self.path以及self.result两个用来存储结果。
解决问题2:终止条件是什么?当数组中的全部数值都已经取完了,也就是startindex已经到最后了,startindex>=len(nums),的情况也就是到达了叶子结点了,此时终止。
解决问题3:单次回溯的逻辑是什么?横向for,纵向递归。横向的for指的是图中的取1,取2,取3这块。上面的所有都和前一个题一样,现在看一下区别:本题给的有重复的值,也就是遍历过一次下次碰见直接跳过,所以可以先排序。
错误第一版:只有从第一个数开始的,后面的数没有了。因为for循环中的if判断语句应该是i > startindex。

class Solution:
    def __init__(self):
        self.path = []
        self.result = []
    def backtracing(self,nums,startindex):
        self.result.append(self.path.copy())
        for i in range(startindex,len(nums)):
            self.path.append(nums[i])
            if i > 0 and nums[i] == nums[i-1]:
                continue
            else:
                self.backtracing(nums,i+1)
                self.path.pop()
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        self.backtracing(nums,0)
        return self.result

错误第二版:每次遍历都把前面的数值append进去了,应该是先判断这个数在之前有没有用过,如果有的话就在进行append和递归操作。

class Solution:
    def __init__(self):
        self.path = []
        self.result = []
    def backtracing(self,nums,startindex):
        self.result.append(self.path.copy())
        for i in range(startindex,len(nums)):
            self.path.append(nums[i])
            if i > startindex and nums[i] == nums[i-1]:
                continue
            self.backtracing(nums,i+1)
            self.path.pop()
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums = sorted(nums)
        self.backtracing(nums,0)
        return self.result

在这里插入图片描述
错误第三版:说了排序排序!!!没写排序我真服了。

class Solution:
    def __init__(self):
        self.path = []
        self.result = []
    def backtracing(self,nums,startindex):
        self.result.append(self.path.copy())
        for i in range(startindex,len(nums)):
            if i > startindex and nums[i] == nums[i-1]:
                continue
            self.path.append(nums[i])
            self.backtracing(nums,i+1)
            self.path.pop()
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        self.backtracing(nums,0)
        return self.result

在这里插入图片描述
正确代码

class Solution:
    def __init__(self):
        self.path = []
        self.result = []
    def backtracing(self,nums,startindex):
        self.result.append(self.path.copy())
        for i in range(startindex,len(nums)):
            if i > startindex and nums[i] == nums[i-1]:
                continue
            self.path.append(nums[i])
            self.backtracing(nums,i+1)
            self.path.pop()
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums = sorted(nums)
        self.backtracing(nums,0)
        return self.result

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值