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

力扣416:分割等和子集

力扣416:分割等和子集

  • 题目
  • 思路
  • 代码

题目

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

思路

我们先从最简单的思路开始想起,一个数组想要分成两个子集并且子集和相同那么这个数组的和必须是奇数并且数组的大小必须大于2。所以我们可以先对这两个进行判断,其次在求数组和时我们还可以求一下数组的最大元素,然后我们把数组和除2也就得到了两个子集的和target,我们再用子集和和数组的最大元素进行比较,如果最大元素已经大于子集和了也就可以返回false了因为最大元素已经大于子集和了其他的所有元素加起来都不可能等于子集和了。
那么在对特殊情况进行判断也就是剪枝之后我们就可以判断正常情况了,在去掉前面的情况后现在的题目就变成了在数组中是否有一个子序列的序列和为target。在进行问题转换后我们可以来思考一个问题,我们是不是可以把这个问题拆分开来也就是形成一个一个的子问题,那么子问题是什么呢?我们设置i为数组的下标,j为目标值,子问题就是数组的前i个数字是否有一种选法让和为j。那么这个i的范围就是[0,nums.size()),j的范围就是[0,target],所以我们可以定义一个二维数组dp,dp[i][j]就是数组nums的前i个元素是否有一种选择方式可以让和为j,如果有就设为true没有就设为false,有子问题有dp数组这不就是动态规划吗。
在定义了dp数组后我们先来判断边界问题也就是i和j分别为0的情况,当i为0的时说明我们只有一个数字可以选择所以dp[0][nums[0]] = true,当j为0时目标值为0所以无论i为多少我们肯定能得到目标值所以dp[i][0] = true。
在解决了边界问题后我们就要解决普遍情况了,也就是推导状态转移方程即dp[i][j] = ?,我们有两个值可以拿来用一个是当前值nums[i]一个是目标值j,这两个值之间有什么关系吗。当然是有的,如果当前值大于目标值说明这个值不能被选,如果当前值小于目标值说明这个值可以被选也可以不被选,总的来说一个值只有选和被选两种情况。

  1. 被选
    当一个值要被选择时,我们想要判断选上这个数字nums[i]后是否等于j就需要考虑上一个数字nums[i-1]以及目标值j-nums[i]。因为我们选上这个数后前面的子序列的和必须是j-nums[i]。
    所以一个数被选择后
    dp[i][j]=dp[i−1][j−nums[i]]dp[i][j] = dp[i-1][j-nums[i]] dp[i][j]=dp[i1][jnums[i]]
  2. 不被选
    当一个值不被选时我们就只需要考虑前一个数字和当前目标值的是否满足条件了
    dp[i][j]=dp[i−1][j]dp[i][j] = dp[i-1][j] dp[i][j]=dp[i1][j]

所以总的状态转移方程是
dp[i][j]={dp[i−1][j−nums[i]]∣dp[i−1][j](j>=nums[i])dp[i−1][j](j<nums[i])}dp[i][j] = \begin{Bmatrix}dp[i-1][j-nums[i]]| dp[i-1][j] (j >= nums[i]) \\dp[i-1][j](j < nums[i])\end{Bmatrix} dp[i][j]={dp[i1][jnums[i]]dp[i1][j](j>=nums[i])dp[i1][j](j<nums[i])}

代码

class Solution {
public:bool canPartition(vector<int>& nums) {int n = nums.size();if (n < 2) {return false;}int total = 0;int maxnumber = INT_MIN;for (int i = 0; i < n; i++) {total += nums[i];maxnumber = max(maxnumber, nums[i]);}// 数组和为奇数则不可能分为两个子集if (total % 2 != 0) {return false;}int target = total / 2;// 如果最大值小于数组和的一半就说明其他的数加起来也不可能等于最大的数if (maxnumber > target) {return false;}// n行,target+1列// 行代表是数组的前几个数// 列代表的是目标值是多少// dp[i][j]里存储的就是这前几个数有没有可能和为目标值vector<vector<int>> dp(n, vector<int>(target + 1, 0));// 列为0时目标值为0,当然有可能for (int i = 0; i < n; i++) {dp[i][0] = true;}// 行为0时只有一个数可以被选,对应的位置为truedp[0][nums[0]] = true;// 非特殊位置for (int i = 1; i < n; i++) {for (int j = 1; j <= target; j++) {// 判断j和num[i]的大小关系if (j >= nums[i]) {// 如果j大于等于nums[i]就说明这个数字是可以被选也可以不被选的// 被选时dp[i][j]的值就取决于dp[i-1][j-nums[i]]// 不被选dp[i][j]的值取决于dp[i-1][j]dp[i][j] = dp[i - 1][j - nums[i]] | dp[i - 1][j];} else {// j小于nums[i]说明这个值不能被选dp[i][j] = dp[i - 1][j];}}}return dp[n - 1][target];}
};
http://www.xdnf.cn/news/20106.html

相关文章:

  • 【无GGuF版本】如何在Colab下T4运行gpt-oss 20B
  • spring事物失效场景
  • MySQL主从同步--主从复制进阶
  • Java 提取 PDF 文件内容:告别手动复制粘贴,拥抱自动化解析!
  • 生成模型实战 | 深度分层变分自编码器(Nouveau VAE,NVAE)
  • 华为在国内搞的研发基地有多野?标杆游学带你解锁“研发界顶流”
  • leetcode算法刷题的第二十七天
  • 【开题答辩全过程】以 高校教室管理系统为例,包含答辩的问题和答案
  • 24V降12V,8A,电路设计,WD5030L
  • 2025年- H118-Lc86. 分隔链表(链表)--Java版
  • 工厂办公环境如何实现一台服务器多人共享办公
  • 【AI论文】Robix:一种面向机器人交互、推理与规划的统一模型
  • 【Java实战㉖】深入Java单元测试:JUnit 5实战指南
  • python代码Bug排查
  • 案例分享|企微智能会话风控系统:为尚丰盈铝业筑牢沟通安全防线
  • 【Vue3+TypeScript】H5项目实现企业微信OAuth2.0授权登录完整指南
  • 医疗问诊陪诊小程序:以人性化设计构建健康服务新生态
  • 微信小程序一个页面同时存在input和textarea,bindkeyboardheightchange相互影响
  • 基于STM32单片机的水位浑浊度检测设计
  • Vue CLI 环境变量和文件加载规则.env文件
  • 《Istio故障溯源:从流量劫持异常到服务网格的底层博弈》
  • AI智能优化SEO关键词策略实战
  • 反序列化的学习笔记
  • Docling将pdf转markdown以及与AI生态集成
  • 23种设计模式——原型模式 (Prototype Pattern)详解
  • Java第十四幕集合啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦
  • LabView学习
  • 迁移学习的案例
  • 嵌入式系统学习Day30(udp)
  • AI架构师的新工具箱:DeepSeek、Copilot、AutoML