代码随想录算法训练营day22和day23 | 77. 组合 216.组合总和III 17.电话号码的字母组合 39. 组合总和 40.组合总和II 131.分割回文串

学习资料:https://programmercarl.com/回溯算法理论基础.html

回溯法backtracking:for循环控制递归数量,暴力搜索:组合、切割、子集、排列、棋盘
今天学了组合和切割
可以画个N叉树的图来帮助理解回溯过程
组合又包括 1.单个数组(要加startIndex参数)或多个数组;2.数组内有无重复元素;3.数组内的元素是否可重复使用
切割:用startIndex来表示🔪的位置
去重的两种对象:同一树层的重复;同一树枝的重复数字
回溯的模板
def backtracking(self, targetSum, k, currenSum, path, result, startIndex):
if 终止条件:
return
for i in range(startIndex, k):
path.append(i)
currentSum += i
self.backtracking(……)
path.pop()
currentSum -= i

学习记录:
77.组合(一个数组,任意K个数组为一组)

点击查看代码
class Solution(object):
    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        result = []
        self.backtracking(n,k,1,[],result)
        return result
        
    def backtracking(self, n, k, startIndex, path, result):
        if len(path) == k:
            result.append(path[:])
            return
        for i in range(startIndex, n+1):
            path.append(i)
            self.backtracking(n,k,i+1,path, result)
            path.pop()
        

216.组合总和3(一个数组,其中几个数和为Target的组合)

点击查看代码
class Solution(object):
    def combinationSum3(self, k, n):
        """
        :type k: int
        :type n: int
        :rtype: List[List[int]]
        """
        result = []
        self.backtracking(n, k, 0, 1, [], result)
        return result

    def backtracking(self, targetSum, k, currentSum, startIndex, path, result):
        """组合用回溯"""
        if currentSum > targetSum:
            return
        # 将满足和为n的路径添加到结果list
        if len(path) == k:
            if currentSum == targetSum:
                result.append(path[:])
            # 注意缩进,不管两种和等不等,都要结束递归
            return  
        for i in range(startIndex, 9 - (k - len(path)) + 2):  # 剪枝,没看懂
            currentSum += i
            path.append(i)
            self.backtracking(targetSum, k, currentSum, i+1, path, result)  # 递归
            currentSum -= i  # 回溯
            path.pop()       # 回溯

17.电话号码的字母组合(__init__初始化中设置字母map数组,多个数组,几个数字就有几个数组,不用startIndex)

点击查看代码
class Solution(object):
    def __init__(self):
        self.letterMap = [
            "",
            "",
            "abc",
            "def",
            "ghi",
            "jkl",
            "mno",
            "pqrs",
            "tuv",
            "wxyz"
        ]
        self.result = []
        self.s = ""
    
    def backtracking(self, digits, index):
        if index == len(digits):
            self.result.append(self.s)
            return
        digit = int(digits[index])
        letters = self.letterMap[digit]
        for i in range(len(letters)):
            self.s += letters[i]
            self.backtracking(digits, index+1)
            self.s = self.s[:-1]


    def letterCombinations(self, digits):
        """
        :type digits: str
        :rtype: List[str]
        """
        if len(digits) == 0:
            return self.result
        self.backtracking(digits, 0)
        return self.result
        

39.组合总和(一个无重复元素的数组,求几个元素的和为target的组合;currentSum == target时终止)

点击查看代码
class Solution(object):
    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        result = []
        self.backtracking(candidates, target, 0, [], result, 0)
        return result

    def backtracking(self, nums, target, current_sum, path, result, startIndex):
        """回溯来控制递归次数"""
        if current_sum > target:
            return
        if current_sum == target:
            result.append(path[:])
            return
        
        for i in range(startIndex, len(nums)):
            current_sum += nums[i]
            path.append(nums[i])
            self.backtracking(nums, target, current_sum, path, result, i)   # 因为数组可重复使用,从i开始而非i+1
            current_sum -= nums[i]
            path.pop()

        

40.组合总和2(一个可有重复数字的数组,但是各个组合之间不能重复,去重的是同一树层;终止条件要加一个:对nums排序,if i>startIndex and nums[i]==nums[i-1]则终止)

点击查看代码
class Solution(object):
    def backtracking(self, nums, target, currentSum, path, result, startIndex):
        if currentSum == target:     # 终止条件1
            result.append(path[:])
        for i in range(startIndex, len(nums)):
            # 本题去重:同一树层的数值要不同,排序后的数组只需判断前后是否相等即可。若重复就跳出本次循环
            if i>startIndex and nums[i] == nums[i-1]:
                continue
            if currentSum + nums[i] > target:
                return
            currentSum += nums[i]
            path.append(nums[i])
            self.backtracking(nums, target, currentSum, path, result, i+1) # 递归,这里数组同一元素只能用一次就从i+1开始
            # 回溯
            currentSum -= nums[i]
            path.pop()



    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        result = []
        candidates.sort()     # 给数组排序,对应于backtracking里的去重一步
        self.backtracking(candidates, target, 0, [], result, 0)    
        return result
        

131.分割回文串(切割,加个判断是否回文的函数,套到回溯函数中;终止条件:startIndex能达到len(string);for循环里要先判断子串是否为回文,不是则跳出本次循环)

点击查看代码
class Solution(object):
    def isPalindrome(self, s, left, right):
        """用双指针法判断字符串是否为回文串"""
        while left<right:
            if s[left] != s[right]:
                return False
            left += 1
            right -= 1
        return True

    def backtracking(self, s, cut_s, startIndex, path, result):
        """回溯法:for循环+单层递归+回溯,达到控制递归数量的目的"""
        # 本题设置只有是回文串才有资格继续向下递归,所以能到最深一层的都是结果
        if startIndex == len(s):
            result.append(path[:])
            return
        
        for i in range(startIndex, len(s)):
            if self.isPalindrome(s, startIndex, i):
                path.append(s[startIndex:i+1])   # 这里切割得到字符串
                # 递归,不能重复使用,则i+1
                self.backtracking(s, cut_s, i+1, path, result)
                path.pop()  # 回溯

    def partition(self, s):
        """
        :type s: str
        :rtype: List[List[str]]
        """
        result = []
        self.backtracking(s, '', 0, [], result)
        return result
    
        

PS:昨天早上起得早又去听课实在没有精力学完算法,今天直接加量学习回溯,一套“组合拳”下来,有点爽到了,就是累得很
今天吃了好吃的炒饭,不过有点咸
天气很好,心情也很好,但是还是挺冷的
突然发现中午学效果贼好

posted @   Tristan241001  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示