代码随想录算法训练营第二十七天丨39. 组合总和、40. 组合总和 II、131. 分割回文串

39. 组合总和

回溯,startIndex不是i+1表示可以重复,另外,先对candidates排序,当remaining<canditates[i]时,直接停止循环,因为后面均不可能有解了。

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        path = []
        candidates.sort()  # 排序

        def backtrack(start, remaining):
            if remaining == 0:
                res.append(path[:])
                return
            for i in range(start, len(candidates)):
                if candidates[i] > remaining:  # 提前终止搜索
                    break
                path.append(candidates[i])
                backtrack(i, remaining - candidates[i])
                path.pop()

        backtrack(0, target)
        return res

40. 组合总和 II

去重逻辑:先排序,遇到与前一个相同的元素跳过本次循环。我在写代码的时候遇到的错误是写成了:

if i > 0 and candidates[i] == candidates[i - 1]:
    continue

后来想想有点好笑,明明已经想到排序了还是没写对;还是没有彻底理解循环嵌套递归每一层和同一层的情况。同一层的for循环中是从startIndex开始,而且去重也是同层去重,同层for循环是在枚举,递归是在填充。

正确代码如下:

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        path = []
        candidates.sort()

        def backtrack(start, remaining):
            if remaining == 0:
                res.append(path[:])
                return 
            if remaining < 0:
                return
            
            for i in range(start, len(candidates)):
                if i > start and candidates[i] == candidates[i - 1]:
                    continue
                if remaining < candidates[i]:
                    break
                path.append(candidates[i])
                backtrack(i + 1, remaining - candidates[i])
                path.pop()

        backtrack(0, target)
        return res

代码随想录上的used数组的写法关键在于如果used[i - 1]是False,说明跟前面枚举过的相等元素不在同一分支上,这时候进行去重,其实不是很能理解必要性。

131. 分割回文串

循环

  • 循环遍历的是字符串 s 的所有可能的子串。对于每个起始位置 start,循环考虑从 start 到字符串末尾的所有可能的结束位置 end
  • 在每次循环迭代中,它创建一个从 startend 的子串(sub = s[start:end]),并检查这个子串是否是回文。
  • 循环的作用是在每个特定的起始位置 start,探索所有可能的结束位置 end,以此来尝试不同的子串分割。

递归

  • 递归函数 backtrack 负责探索从当前位置 start 开始的所有分割方案。
  • 每当找到一个回文子串时,递归函数会将这个子串加入到当前分割方案 parts 中,并从这个子串的下一个位置(end)递归地继续探索。
  • 递归的作用是深入每一个可能的分割点,继续探索从这个点开始的所有分割方案,直到到达字符串的末尾。
  • 递归允许代码“记住”当前的分割状态(即 parts 中的内容),并在每一层递归中基于此继续探索。
class Solution:
    def partition(self, s: str) -> List[List[str]]:
        res = []
        parts = []

        def backtrack(start):
            if start >= len(s):
                res.append(parts[:])

            for end in range(start + 1, len(s) + 1):
                sub = s[start:end]
                if sub == sub[::-1]:
                    parts.append(sub)
                    backtrack(end)
                    parts.pop()
        backtrack(0)
        return res

抽象,第一次见做不出来。

今日总结:

有点自闭,但是又好像能理解一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值