LeetCode刷题 | Day 3 分割等和子集(Partition Equal Subset Sum)自顶向下动态规划算法

这篇博客详细介绍了LeetCode第416题《分割等和子集》的解题方法,主要采用自顶向下的动态规划策略。通过计算数组总和判断奇偶性,再定义递归函数dp(i, s)寻找和为目标值的子集。当总和为偶数时,递归检查是否能形成和为总和一半的子集,利用Python的@cache装饰器避免重复计算。博客还包含了Python和C++的实现代码。" 89499992,1067960,MXNet安装指南,"['深度学习', '框架', 'MXNet', 'Python库', '安装教程']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode刷题 | Day 3 分割等和子集(Partition Equal Subset Sum)自顶向下动态规划算法



前言

LeetCode位置:416. 分割等和子集

日常刷题,维持手感,同步学习英语,刷题顺序参考B站UP@justyyuk的系列视频,感兴趣的点波关注。
学海无涯,大路千万,感恩此程,彼此真诚陪伴!
在这里插入图片描述
Ps:第一次刷到的道友留步,这里拉齐一下信息。文章主要记录视频中的主要内容,算法思路会按照个人理解,用伪代码+举例每步输出的方式呈现。代码部分会以Python和C++语法进行呈现。文章最后会总结一些英语词汇。OK,就啰嗦这么多,开始进步[干杯🐱‍👓]


一、题目概述

Day3

输入:nums列表
输出:bool值,表示原始列表是否存在和相等的两个子列表

PS:

  1. 子序列 (Subsequence/Subset):

    • 子序列是通过从原始序列中删除一些或不删除任何元素且不改变剩余元素顺序而得到的序列。
    • 例子:对于序列 [1, 2, 3, 4],[1, 3, 4] 和 [2, 4] 是子序列。
    • 注意:[1, 4, 3] 不是 子序列,因为顺序改变了。
  2. 子列表 (Sublist)

    • 子列表是列表的连续部分,意味着元素必须是连续的。
    • 例子:对于列表 [1, 2, 3, 4],[2, 3] 和 [1, 2, 3]是子列表。
    • 注意:[1, 3] 不是 子列表,因为它不是连续的。
  3. 子数组 (Subarray):

    • 类似于子列表,子数组是数组的连续部分。
    • 例子:对于数组 [1, 2, 3, 4],[2, 3] 和 [1, 2, 3] 是子数组。
    • 注意:[1, 3] 不是 子数组,因为它不是连续的。
  • 在许多情况下,当数据结构是数组或列表时,“子列表”和“子数组”可以互换使用,但“子数组”一词专门用于数组。

二、解题方法

2.1 动态规划思想

2.1.1 思路讲解

Ps: 动态规划(Dynamic Programming)特征
- 最优子结构:
- 动态规划要求问题具有最优子结构性质,即问题的最优解包含其子问题的最优解。
- 重叠子问题:
- 动态规划需要问题具有重叠子问题性质,即不同的子问题在求解时会重复出现。
- 状态转移方程:
- 动态规划通过状态转移方程将问题分解为子问题,并通过子问题的解来推导原问题的解。
- 全局最优解:
- 动态规划通过考察所有可能的子问题组合来确保找到全局最优解。
- 记忆化或表格法:
- 动态规划通常使用记忆化搜索或自底向上的表格法来避免重复计算。

  • 动态规划策略

    • 本题思路主要是通过递归的方式遍历到任意一个数组的全部子序列,然后在遍历的过程中判断当前子序列是否满足和为原数组一半的条件。
  • 具体步骤

    1. 求和与奇偶性检查:

      • 先计算数组 nums 的总和 total。 如果 total 是奇数,则不可能将数组分成两个和相等的子集,因为奇数不能被均分,所以直接返回False。 如果 total 是偶数,那么我们需要找到一个子集,其和为 total // 2,称之为 half。
    2. 递归与缓存:

      • 定义一个递归函数 dp(i, s),表示在考虑前 i 个元素的情况下,是否可以得到和为 s 的子集。
    3. 利用 Python 的 @cache

      • 装饰器(或者等价的 functools.lru_cache)来缓存递归结果,避免重复计算,提高效率。
    4. 递归的边界条件与状态转移:

      • 边界条件: 如果 i 达到了数组 nums 的末尾,则检查 s 是否为 0。如果是 0,表示找到了符合条件的子集,返回 True;否则返回False。
      • 如果 s 为 0,表示当前子集和已经达到了目标,返回 True。 如果 s 小于 0,表示当前路径不可能达成目标,返回False。
    5. 状态转移:

      • 我们有两个选择:包括当前元素 nums[i] 或不包括它。
        对于这两种选择,递归检查任意一种选择能否达成目标子集和。

2.1.2 伪代码 + 逐步输出示例

# 伪代码示例
函数 canPartition(nums):
	total = nums 的和
	如果 total 是奇数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上坤

涓涓细流,生活不易

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值