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,3] 和 [3,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()
相关推荐
cmpxr_1 天前
【C】数组名、函数名的特殊
c语言·算法
KAU的云实验台1 天前
【算法精解】AIR期刊算法IAGWO:引入速度概念与逆多元二次权重,可应对高维/工程问题(附Matlab源码)
开发语言·算法·matlab
会编程的土豆1 天前
【数据结构与算法】再次全面了解LCS底层
开发语言·数据结构·c++·算法
大熊背1 天前
如何利用Lv值实现三级降帧
算法·自动曝光·lv·isppipeline
大尚来也1 天前
驾驭并发:.NET多线程编程的挑战与破局之道
java·前端·算法
向阳而生,一路生花1 天前
深入浅出 JDK7 HashMap 源码分析
算法·哈希算法
君义_noip1 天前
信息学奥赛一本通 4150:【GESP2509七级】⾦币收集 | 洛谷 P14078 [GESP202509 七级] 金币收集
c++·算法·gesp·信息学奥赛·csp-s
摸个小yu1 天前
【力扣LeetCode热题h100】链表、二叉树
算法·leetcode·链表
汀、人工智能1 天前
[特殊字符] 第93课:太平洋大西洋水流问题
数据结构·算法·数据库架构·图论·bfs·太平洋大西洋水流问题
ZPC82101 天前
rviz2 仿真控制器与真实机器人切换
人工智能·算法·机器人