day20-数据结构力扣

没有刚开始学习的时候热血了,我也不知道我还能坚持多久

39. 组合总和

题目链接 39. 组合总和 - 力扣(LeetCode)

思路

先贴一个我最开始写的代码,超出时间限制的

python 复制代码
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res=[]
        self.backtrack(candidates,target,[],res)
        return res

    def backtrack(self,candidates,target,path,res):
        if sum(path)==target:
            res.append(path[:])
            return

        for num in candidates:  # 错误 1
            path.append(num)
            self.backtrack(candidates,target-sum(path),path,res)  # 错误 2、3
            path.pop()

错误 1:每次都从头遍历 candidates → 产生重复组合

比如 [2,3][3,2] 都会被算进去!因为你每次递归都重新从第一个数开始选

题目要求:组合不看顺序,2,33,2 算同一个!

错误 2:没有判断 sum (path) > target → 无限递归 / 栈溢出

比如 candidates=2, target=1你会一直加 2 → sum=2 → 超过 target 但不停止 → 死循环。

错误 3:每次都用 sum (path) → 超级慢、效率极低

递归里反复求和,时间复杂度爆炸。正确做法是用减法,而不是每次求和。

修改

python 复制代码
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        self.backtrack(candidates, target, 0, [], res)  # 加 start=0
        return res

    def backtrack(self, candidates, target, start, path, res):
        if target == 0:  # 不用 sum(path),用减法更快
            res.append(path.copy())
            return
        
        # 从 start 开始,不回头 → 去重
        for i in range(start, len(candidates)):
            num = candidates[i]
            
            if num > target:  # 剪枝,避免死循环
                continue
            
            path.append(num)
            self.backtrack(candidates, target - num, i, path, res)  # 传 i,可重复选
            path.pop()
  • 用 start 保证不回头(去重)

  • 用 target - num 减法(高效)

  • 用 if num>target 剪枝(防死循环)

  • 递归传 i(可重复选)

提交

python 复制代码
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res=[]
        self.backtrack(candidates,target,0,[],res)
        return res

    def backtrack(self,candidates,target,start,path,res):
        if target==0:
            res.append(path[:])
            return

        for i in range(start,len(candidates)):
            num=candidates[i]
            if target<0:
                return
            path.append(num)
            self.backtrack(candidates,target-num,i,path,res)
            path.pop()

40.组合总和II

题目链接40. 组合总和 II - 力扣(LeetCode)

思路

真的很绕,一会不同层,一会去重,一会剪枝

这个题和上题不同之处

  1. 上一题 :同一个数字可以无限制重复选

  2. 这一题 :每个数字只能用一次

  3. 这一题额外 :candidates 里本身有重复数字 ,要保证结果不重复

第一处改动:

上题(可重复选)

python 复制代码
# 1. 递归传 i,表示还能再选当前数
self.backtrack(candidates, target - num, i, path, res)

本题(不能重复选)

python 复制代码
# 1. 递归传 i+1,表示下一次只能选下一个数
self.backtrack(candidates, target - num, i+1, path, res)

第二处改动(去重,因为数组有重复数字):

本题

python 复制代码
# 跳过同层重复元素,避免结果重复
if i > start and candidates[i] == candidates[i-1]:
    continue
题目 递归传什么 是否要排序去重
可重复选 i 不需要
不可重复选 i+1 需要(必须排序 + 去重)

允许的重复:

不同层 → 纵向重复 [1,1,6]

禁止的重复:

同一层 → 横向重复 [1(第一个), ...][1(第二个), ...]

同层去重,是为了不让结果重复

提交

python 复制代码
from typing import List

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        candidates.sort()  # 必须排序!方便去重
        self.backtrack(candidates, target, 0, [], res)
        return res

    def backtrack(self, candidates, target, start, path, res):
        if target == 0:
            res.append(path.copy())
            return
        
        for i in range(start, len(candidates)):
            num = candidates[i]
            
            # 剪枝
            if num > target:
                continue
            
            # 去重关键:同层不能选相同数字
            if i > start and candidates[i] == candidates[i-1]:
                continue
            
            path.append(num)
            # 重点:传 i+1,不能重复用当前数
            self.backtrack(candidates, target - num, i + 1, path, res)
            path.pop()

131.分割回文串

题目链接

思路

示例错误写法

python 复制代码
class Solution:
    def partition(self, s: str) -> List[List[str]]:
        res=[]
        self.backtrack(s,0,[],res)
        return res

    def backtrack(self,s,start,path,res):
        if path!=[] and path==path[::-1]:
            res.append(','.join(path))
            return 

        for i in range(start,len(s)):
            path.append(s[i])
            self.backtrack(s,i+1,path,res)
            path.pop()
  • 判断的是 整个 path 是不是回文

  • 应该判断 当前切的这一小段 s start:i+1 是不是回文

  • 把字符一个个加进去 path.append(s[i])

  • 应该直接切一段 加进去 path.append(s[start:i+1])

提交

python 复制代码
class Solution:
    def partition(self, s: str):
        res = []
        self.backtrack(s, 0, [], res)
        return res

    def backtrack(self, s, start, path, res):
        # 切割到最后了,保存答案
        if start == len(s):
            res.append(path.copy())
            return

        # 从 start 开始切一段
        for i in range(start, len(s)):
            substr = s[start:i+1]  # 切一小段
            
            # 只要这一小段是回文,就继续
            if substr == substr[::-1]:
                path.append(substr)
                self.backtrack(s, i+1, path, res)  # 切后面
                path.pop()
相关推荐
HjhIron18 小时前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩19 小时前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹21 小时前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术1 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望1 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法
黄敬峰1 天前
面试必刷:从JS底层包装类到双指针,彻底搞懂字符串与回文算法
算法
地平线开发者2 天前
J6B vio scenario sample
算法
BothSavage2 天前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn2 天前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法