当前位置: 首页 > news >正文

LeetCode 416 - 分割等和子集

在这里插入图片描述
在这里插入图片描述

文章目录

    • 摘要
    • 描述
    • 题解答案
    • 题解代码分析
    • 示例测试及结果
    • 总结

摘要

这道题看似是一个“集合分割”的问题,但核心本质其实是一个典型的 0/1 背包问题。给定一个整数数组,我们需要判断能否将它分成两个子集,使两个子集的和相等。换句话说,就是看看数组中能否选出一部分数字,使它们的和等于整个数组和的一半。
在这篇文章里,我们不仅会用 Swift 实现完整的解法,还会从动态规划的角度详细拆解思路,并给出可运行的 Demo 示例,帮助你更好地理解这类问题在实战开发中能如何类比使用。

描述

题目要求很明确:

给你一个只包含正整数的非空数组 nums,判断是否可以将其分成两个子集,使得两个子集的元素和相等。

举个例子:

输入: nums = [1,5,11,5]
输出: true
解释: 可以分为 [1,5,5] 和 [11]

如果输入是:

nums = [1,2,3,5]
输出: false
解释: 无法分为两个等和子集。

换句话说,我们要判断是否能在数组中找到一些元素,它们的和恰好等于数组总和的一半。

题解答案

这个问题的本质是:是否存在一个子集,其和为 totalSum / 2

因此我们可以使用“动态规划”的思路来解决。
假设数组总和是 sum,如果 sum 是奇数,直接返回 false,因为不可能拆成两个整数和相等的部分。
如果是偶数,那么问题就变成:“能否从数组中选出一些数,使得它们的和等于 sum / 2。”

我们可以定义一个布尔型数组 dp[target] 表示:

是否能从 nums 的部分元素中选出若干个数,使它们的和恰好等于 target

转移方程:

dp[j] = dp[j] || dp[j - num]

(即:如果不选 num,dp[j] 保持原值;如果选 num,只要 dp[j - num] 为真即可。)

最后返回 dp[target] 是否为真。

题解代码分析

下面是完整的 Swift 实现代码,并带详细注释:

import Foundationclass Solution {func canPartition(_ nums: [Int]) -> Bool {// 1. 计算数组总和let totalSum = nums.reduce(0, +)// 2. 如果总和是奇数,不可能分割成相等的两部分if totalSum % 2 != 0 { return false }let target = totalSum / 2let n = nums.count// 3. 创建一维 DP 数组,表示能否组成和为 jvar dp = Array(repeating: false, count: target + 1)dp[0] = true  // 和为0总是可以实现(什么都不选)// 4. 遍历数组,每个数字只能用一次(0/1背包)for num in nums {// 注意要倒序遍历,防止重复使用同一个数for j in stride(from: target, through: num, by: -1) {dp[j] = dp[j] || dp[j - num]}}// 5. 结果:能否恰好拼出 targetreturn dp[target]}
}

这段代码的核心逻辑在于:

  • 使用一维动态规划数组,节省空间;
  • 倒序更新 dp,确保每个元素只使用一次;
  • 时间复杂度为 O(n * target),在数据范围内表现很优。

示例测试及结果

我们写一个简单的测试 Demo 来验证代码运行效果:

let solution = Solution()print(solution.canPartition([1, 5, 11, 5]))  // 输出 true
print(solution.canPartition([1, 2, 3, 5]))   // 输出 false
print(solution.canPartition([2, 2, 3, 5]))   // 输出 false
print(solution.canPartition([1, 2, 5]))      // 输出 false
print(solution.canPartition([1, 1, 1, 2, 2])) // 输出 true

运行结果:

true
false
false
false
true

这些结果完全符合题意。
尤其是 [1,1,1,2,2] 这个例子,很容易出错:
它能分为 [1,1,2][1,2],两边都是 4,说明算法逻辑正确。

时间复杂度

动态规划部分的循环是 n * target,其中:

  • n 是数组长度(最大 200)
  • targetsum / 2,最大约为 10000

所以时间复杂度为:

O(n * target)

在本题范围内完全可行。

空间复杂度

我们只用了一个长度为 target + 1 的一维数组:

O(target)

如果使用二维 DP(传统写法),空间会是 O(n * target),但在这里我们做了优化,减少了空间占用。

总结

这道题的核心是将“集合分割”转化为“背包问题”:

  • 用动态规划的方式判断能否拼出目标和;
  • 从二维优化为一维后,代码更简洁、效率更高;
  • 核心点在于:从后往前更新 dp 数组,防止重复使用同一个元素
http://www.dtcms.com/a/574810.html

相关文章:

  • 网站开发命名规范iis创建网站
  • 物流公司网站 源码开发区邮编
  • 做网站需要给设计提供网络营销策划是什么
  • 香港科技大学广州|智能交通学域博士招生宣讲会—湖南大学专场
  • 哪家网站开发好wordpress 禁止头像
  • 淘宝网站开发网站开发恶意索赔
  • Python+Requests零基础系统掌握接口自动化测试
  • 建设网站的硬件影视公司简介
  • 北京网站建设seo公司哪家好免费做字体的网站好
  • 淘宝客网站搭建教程能推广的平台有哪些
  • 坪地网站建设如何wordpress博客下载插件
  • 做外贸要访问国外的网站怎么办携程网网站是哪家公司做的
  • dz网站模板新河网新河吧
  • Ubuntu22.04 ros2-humble 源码安装 Moveit2
  • 网站开发需求表模板制作小企业网站
  • 南宁公司做网站佛山企业网站建设渠道
  • 从山海经取公司名三个字无锡优化网站排名
  • 旅游网站系统设计wordpress多重搜索
  • php快速建站系统广西建设网登录入口
  • 高端网站开发案例展示做网站傻瓜
  • 于丹确认出席创客匠人 2025 峰会:AI 时代,用人文为技术与 IP 注入灵魂
  • 网站投票制作seo优化排名百度教程
  • 卡盟自助网站建设连锁加盟网络营销公司
  • 网站开发是指视频拍摄案例
  • 第十六届蓝桥杯省赛 C 组——Java题解1(链表知识点)
  • 金仓KReplay:定义数据库平滑迁移新标准
  • 网站建设大型企业微商城平台排行榜前十名
  • 巩义企业网站托管服务商国内网站欣赏
  • TDengine 字符串函数 CONCAT 用户手册
  • 怎样做网站备份网络设计项目