494.目标和

news2025/7/19 6:40:22

在这里插入图片描述

1. 回溯算法

这题和之前做的那些排列、组合的回溯稍微有些不同,你不需要每次选数据时都是for遍历去选择,很明显这是顺序选择的
比如 数组[0,1],target=1;
在这里插入图片描述
递归数组,每个元素都 + 或者 - ,然后取最后结果为0的即可

class Solution {
     public int findTargetSumWays(int[] nums, int target) {
        find(0,nums,target);
        return count;
    }

    private void find(int begin,int[] nums,int target){
        // 如果减完了,结束
        if(begin == nums.length){
            if(target == 0){
                count++;
            }
            return;
        }
        target-=nums[begin];
        find(begin+1,nums,target);
        target+=nums[begin];

        target+=nums[begin];
        find(begin+1,nums,target);
        target-=nums[begin];   
        
    }
    private int count=0;
}

2. 动态规划

这其实可以抽象为0/1背包问题。
数组中的元素,要么是前面+,要么是前面-,问计算结果为target的方案有多少种。
计算结果为0,即我们把前面为+的元素放在一个集合A中,前面为-的元素放在一个集合B中,二者之差为target即可。
我们如果知道了集合A,那么集合B自然就是数组中剩余元素组成。

可以列个简单的数学公式,假设A集合元素的和为left,B元素和为right,数组总和为sum

left + right = sum;
left - right = target;

二者一相加可以得到 left=(sum+target)/2;
由于都是正整数,left如果不是正整数,说明无解,即没有这种方案。

思路成功转换为,背包容量为left,在数组中找出和刚好为left的方案,并记录方案的最大数。

  1. 确定dp[i][j]

即dp[i][j] :在数组中下标为0~i的元素中任选,和刚好为j的方案数量

  1. 确定递推公式
    如果第i个元素不选,那方案数量和dp[i-1][j]的一样
    dp[i][j] = dp[i-1][j]
    如果选了第i个元素,那方案就不仅仅从i-1个元素选出和为j的,从i-1个元素选出和为j-nums[i]的也可以,两种方案数相加。
    dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]

  2. 如何初始化
    dp[0][0]=1 我可以都不选,那方案数就是1
    初始化第一行 dp[0][nums[0]]+=1;
    题目中提示给出nums[i]范围是可能为0,所以如果nums[0]=0,那就是dp[0][0]中都不选的方案中,再添加一种,选择元素0,那就是两个方案了!!!
    重点细节,卡了我一个上午!!!

  3. 确定遍历顺序
    先数组元素,再背包容量

  4. 模拟推导

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        if(nums.length == 1){
            return target == nums[0]?1:target == 0-nums[0]?1:0;
        }
        // 把集合分成前面放+的正集合和前面放-的负集合.正集合的和为left,负集合的和为right
        // left+right=sum left-right=target => left = (target+sum)/2
        // 即转换为问题---把背包容量为left的背包装满有多少种方案
        // 同时,如果left不为整数,说明不行,返回0

        // dp[i][j] 在下标0为~i的元素中,填满背包容量为j,有多少种方案
        // dp[i][j] = dp[i-1][j] 如果不装i
        // dp[i][j] = Math.max(dp[i-1][j-nums[i]],dp[i-1][j]) 如果装i
        int sum=0;
        for(int i:nums){
            sum += i;
        }
        if((target+sum)%2 != 0 ){
            return 0;
        }

        if(target > sum || target < -sum){
            return 0;
        }
        int num = (target+sum)/2;
        num = num < 0?-num:num;

        int[][] dp = new int[nums.length][num+1];

        // 当容量为0的时候,都不选就是一种方案
        for(int i=0;i<nums.length;i++){
            dp[i][0]=1;
        }
        // 遍历第一行,dp[0][nums[0]]+=1 因为可能第一行中nums[0]=0,此时dp[0][0]其实已经初始化为1了,但是dp[0][0]其实有两个方案的,一个是都不选,一个是选了0,这个细节决定了我们后续的遍历从第二行开始是否成功!!!
        if(nums[0]<num+1){
            dp[0][nums[0]]+=1;
        }

        for(int i=1;i<nums.length;i++){
            for(int j=0;j<num+1;j++){
                dp[i][j] = dp[i-1][j];
                if(j>=nums[i]){
                    dp[i][j] = dp[i-1][j-nums[i]] + dp[i-1][j];   
                } 
            }
        }
        return dp[nums.length-1][num];
    }
}

优化成一维的

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        if(nums.length == 1){
            return target == nums[0]?1:target == 0-nums[0]?1:0;
        }
        // 把集合分成前面放+的正集合和前面放-的负集合.正集合的和为left,负集合的和为right
        // left+right=sum left-right=target => left = (target+sum)/2
        // 即转换为问题---把背包容量为left的背包装满有多少种方案
        // 同时,如果left不为整数,说明不行,返回0

        // dp[i][j] 在下标0为~i的元素中,填满背包容量为j,有多少种方案
        // dp[i][j] = dp[i-1][j] 如果不装i
        // dp[i][j] = Math.max(dp[i-1][j-nums[i]],dp[i-1][j]) 如果装i
        int sum=0;
        for(int i:nums){
            sum += i;
        }
        if((target+sum)%2 != 0 ){
            return 0;
        }

        if(target > sum || target < -sum){
            return 0;
        }
        int num = (target+sum)/2;
        num = num < 0?-num:num;

        int[]dp = new int[num+1];
        // 当容量为0的时候,都不选就是一种方案
        dp[0]=1;

       // 遍历第一行
        if(nums[0]<num+1){
            dp[nums[0]]+=1;
        }

        for(int i=1;i<nums.length;i++){
            for(int j=num;j>=nums[i];j--){
                dp[j] += dp[j-nums[i]]; 
            }
        }
        return dp[num];
    }
}

这道题很经典,建议过段时间重复刷

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/368903.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql是怎样运行的之Inno页介绍

一、InnoDB介绍 InnoDB是一个将表中的数据存储到磁盘上的存储引擎&#xff0c;所以即使关机后重启我们的数据还是存在的。而真正处理数据的过程是发生在内存中的&#xff0c;所以需要把磁盘中的数据加载到内存中&#xff0c;如果是处理写入或修改请求的话&#xff0c;还需要把内…

Java数据结构 —— 手写线性结构(稀疏数组、栈、队列、链表)

目录 稀疏数组 顺序表 链表 单向顺序链表 双向链表 双向循环链表求解约瑟夫环&#xff08;Joseph&#xff09; 栈 顺序栈 队列 顺序队列 顺序循环队列 稀疏数组 当一个数组中大部分值为0,或者相同时&#xff0c;可以采用稀疏数组的方式来保存&#xff0c;从而节约存储…

代码随想录算法训练营day41 | 动态规划 01背包问题基础 01背包问题之滚动数组

01背包问题基础 问题描述 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 举个栗子 背包最大重量为4。 物品为&#xff1a; 重量价值…

文本生成图像简述4——扩散模型、自回归模型、生成对抗网络的对比调研

基于近年来图像处理和语言理解方面的技术突破&#xff0c;融合图像和文本处理的多模态任务获得了广泛的关注并取得了显著成功。 文本生成图像&#xff08;text-to-image&#xff09;是图像和文本处理的多模态任务的一项子任务&#xff0c;其根据给定文本生成符合描述的真实图像…

VUE3源码分析————rollup打包

文章目录什么是rolluprollup打包和webpack打包的区别rollup打包准备一、安装yarn开始rollup打包一、初始化二、package.json文件配置三、新建并配置打包文件夹四、下载rollup及打包执行文件五、文件大致分布![image.png](https://img-blog.csdnimg.cn/img_convert/66f1a85ff57d…

基于servlet学生宿舍管理系统

一、项目简介 本项目是一套javaWeb基于servlet学生宿舍管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&#xff0c;…

【Unity VR开发】结合VRTK4.0:创建物理按钮

语录&#xff1a; 如今我努力奔跑&#xff0c;不过是为了追上那个曾经被寄予厚望的自己 前言&#xff1a; 使用线性关节驱动器和碰撞体从动器可以轻松创建基于物理的按钮&#xff0c;以使交互者能够在物理上按下按钮控件&#xff0c;然后挂钩到驱动器事件中以了解按钮何时被按…

追梦之旅【数据结构篇】——详解C语言实现顺序队列

详解C语言实现顺序队列~&#x1f60e;前言&#x1f64c;预备小知识&#x1f64c;队列的概念及结构&#x1f60a;1.顺序队列头文件编写&#x1f64c;2.Queue.c文件的编写&#x1f64c;1&#xff09;队列的初始化函数实现&#x1f60a;2&#xff09;队列的销毁函数实现&#x1f6…

Leetcode DAY 44: 完全背包 and 零钱兑换 II and 组合总和 Ⅳ

完全背包518. 零钱兑换 II&#xff01;&#xff01;&#xff01;程序未通过原因&#xff1a; 1、dp数组的初始化没考虑清楚 2、组合问题 dp数组的更新没考虑清楚 修改后&#xff1a; class Solution { public:int change(int amount, vector<int>& coins) {// dp[j…

python保留小数函数总结

python保留小数——‘%f’‘%.nf’% x&#xff08;定义的变量&#xff09; 例子&#xff1a;a 82.16332 print(%.1f% a) print(%.2f% a) print(%.3f% a) print(%.4f% a) print(%.10f% a)输出结果python保留小数——format&#xff08;&#xff09;函数Python2.6 开始&#xff…

【Zotero】文献阅读神器Zotero打造个人移动图书馆

1、 将zotero portable版装入移动硬盘 zotero portable下载链接 2、 安装zotfile管理附件 官网&#xff1a;http://zotfile.com/ 下载好之后&#xff0c;打开Zotero&#xff0c;依次点击菜单栏工具&#xff08;tools&#xff09;-插件&#xff08;Add-ons&#xff09;&#…

Vue3 中组件的使用(上)

目录前言&#xff1a;一、什么是组件二、注册组件1. 全局注册2. 局部注册二、传递数据【父 -> 子】1. 字符串数组的形式2. 对象的形式三、组件事件【子 -> 父】1. 字符串数组式声明自定义事件2. 【子组件】触发组件事件3. 【父组件】监听子组件自定义事件4. 组件事件例子…

【大数据】记一次hadoop集群missing block问题排查和数据恢复

问题描述 集群环境总共有2个NN节点&#xff0c;3个JN节点&#xff0c;40个DN节点&#xff0c;基于hadoop-3.3.1的版本。集群采用的双副本&#xff0c;未使用ec纠删码。 问题如下&#xff1a; bin/hdfs fsck -list-corruptfileblocks / The list of corrupt files under path…

AI算法创新赛-人车目标检测竞赛总结04

队伍&#xff1a;AI000038 小组成员&#xff1a;杨志强&#xff0c;林松 1. 算法介绍 1.1 相关工作 当前流行的目标检测算法主要分为三种&#xff0c;一阶段算法&#xff1a;SSD&#xff0c;FCOS&#xff0c;Scaled&#xff0c;YOLO系列等&#xff1b;二阶段算法&#xff1a…

宝塔搭建实战php悟空CRM前后端分离源码-后端server篇(一)

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 有个朋友发消息跟我说&#xff0c;能不能让我录制一期一套开源的悟空CRM系统&#xff0c;然后网上搜了下&#xff0c;搭建起来测试后&#xff0c;感觉还不错&#xff0c;是一套前后端分离的CRM系统&#xff0c;前…

Java浅析电信数据采集

技术&#xff1a;Java等摘要&#xff1a;电信运营系统中&#xff0c;电信计费系统是主要的支撑系统&#xff0c;占有重要地位。对于电信计费系统是电信运营商的核心竞争力之一这一观点愈来愈被业界认同。电信计费系统中的数据蕴含着企业经营态势、客户群分布特征及消费习惯、各…

什么是隔离式数字输入?

隔离式数字输入与数字隔离器虽然它们听起来很相似&#xff0c;但隔离式数字输入和数字隔离器之间实际上存在一些值得注意的差异。看完这篇文章&#xff0c;希望大家能轻松分辨出两种隔离功能的区别。 内部结构 数字隔离器具有提供电流隔离数字信号路径的基本&#xff08;或经…

网易的“草长莺飞二月天”:增长稳健,加码研发,逐浪AI

2月23日&#xff0c;网易发布了2022年第四季度财报。 这是网易与暴雪分道扬镳后的首份财报&#xff0c;加上近期AIGC热度扩散至游戏、教育等各个领域&#xff0c;网易第四季度业绩及其对于GPT等热门技术的探索受到市场关注。 根据财报&#xff0c;第四季度&#xff0c;网易营…

从单管单色到单管RGB,这项MicroLED工艺不可忽视

微显示技术商Porotech&#xff0c;在CES 2023期间展示了最新的MicroLED显示模组。近期&#xff0c;AR/VR光学领域的知名博主Karl Guttag深度分析了该公司的微显示技术&#xff0c;并指出Porotech带来了他见过最有趣的MicroLED技术。Guttag表示&#xff1a;Porotech是本届CES上给…

Airbyte的同步复制模式

ELT 哲学的核心原则&#xff0c;即数据在提取和加载阶段移动时应保持不变&#xff0c;以便始终可以在目标中访问原始数据。由于目标中存在数据的未修改版本&#xff0c;因此将来可以重新转换该版本&#xff0c;而无需从源系统重新同步数据。 基于此哲学&#xff0c;我们看看Air…