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()
相关推荐
AICDragon6 小时前
1.8%就够了:K3的896个MoE专家,为什么激活率这么低反而是好事?
人工智能·算法
VALENIAN瓦伦尼安教学设备6 小时前
ASHOOTER激光对中仪如何通过颜色确定调整是否合适
数据库·嵌入式硬件·算法
货拉拉技术6 小时前
重塑 Agent 度量衡:基于 LLM-as-a-Judge 的离线评估体系与实践
算法·设计模式
车压7 小时前
从“为什么”理解注意力机制
算法
wabs6667 小时前
关于哈希表【力扣15.三数之和的思考】
数据结构·算法·leetcode·散列表·哈希表·三数之和
退休倒计时7 小时前
【每日一题】LeetCode 88. 合并两个有序数组 TypeScript
算法·leetcode·职场和发展·typescript
键盘会跳舞7 小时前
C++:函数对象与 std::function 源码级深度拆解——泛型算法的策略内核与可调用对象统一封装
c++·算法·仿函数
手写码匠7 小时前
华为云Flexus+DeepSeek征文|Agent 评测体系实战:用 DeepSeek-R1 当裁判,打造 Dify Agent 的自动化回归测试流水线
人工智能·深度学习·算法·aigc
LONGZETECH7 小时前
无人机实训高成本痛点解法:虚拟仿真实现 70% 耗材损耗下降
大数据·算法·unity·架构·无人机
不会就选b7 小时前
算法日常・每日刷题--<队列,宽搜>4
算法