LeetCode 494:目标和(Target Sum)—— 题解 ✅

LeetCode 494:目标和(Target Sum)------ 题解 ✅

🔗 题目链接

👉 https://leetcode.cn/problems/target-sum/


📖 内容概要

给定一个非负整数数组 nums 和一个整数 target

你可以在每个数字前加 +-,使计算结果等于 target

返回所有可能的表达式数量。

✅ 0/1 背包(计数问题)

✅ 数学转化是关键

✅ 面试高频题


💡 解题思路(核心)

一、关键数学转化(非常重要)

设:

  • 正数和为 P
  • 负数绝对值和为 N

则有:

复制代码
P - N = target
P + N = sum

解得:

复制代码
P = (sum + target) / 2

👉 问题转化为:

从数组中选出若干数,使其和正好等于 P


二、不可行的情况(剪枝)

情况 原因
(sum + target) 为奇数 无法整除
` target
java 复制代码
if ((sum + target) % 2 == 1) return 0;
if (Math.abs(target) > sum) return 0;

三、DP 定义

java 复制代码
dp[j] = 和为 j 的方案数

四、状态转移方程

java 复制代码
dp[j] += dp[j - nums[i]];

✅ 每个数只能用一次

✅ 倒序遍历(0/1 背包)


五、初始化

java 复制代码
dp[0] = 1;

什么都不选,是一种方案


✅ AC 代码(Java)

java 复制代码
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int a : nums) {
            sum += a;
        }

        int left = (sum + target) / 2;

        // 剪枝
        if ((sum + target) % 2 == 1) return 0;
        if (Math.abs(target) > sum) return 0;

        int[] dp = new int[left + 1];
        dp[0] = 1;

        // 0/1 背包(计数)
        for (int i = 0; i < nums.length; i++) {
            for (int j = left; j >= nums[i]; j--) {
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[left];
    }
}

⏱️ 复杂度分析

指标 复杂度
时间复杂度 O(n × sum)
空间复杂度 O(sum)

🔍 与 416 / 1049 的对比

题目 目标
416. 分割等和子集 是否存在
1049. 最后一块石头 II 最小差值
494. 目标和 方案数

✅ 三题本质都是 子集和问题

✅ 区别在于 DP 含义不同


✅ 一句话总结

把"加减符号问题"转化为"子集和为 P 的方案数问题",再用 0/1 背包计数。


📌 面试加分点(建议记住)

  • ✅ 为什么是 (sum + target) / 2
  • ✅ 为什么 dp[0] = 1
  • ✅ 为什么是 += 而不是 max
  • ✅ 与回溯法的对比(会超时)
相关推荐
To_OC10 小时前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode
05Kevin1 天前
lk每日冒险题--数据结构6.27
算法
To_OC1 天前
从一次栈溢出报错说起,我把递归彻底扒明白了
javascript·算法·程序员
千纸鹤安安2 天前
千问Qwen-AgentWorld来了:一个语言模型搞定七大Agent场景,GPT-5.4都输了
算法
七牛开发者2 天前
MCP 到底是什么?为什么 Agent 都想接上它
算法·aigc·agent
kisshyshy2 天前
从递归到迭代,一文吃透二叉树的核心知识与 JavaScript 实现
javascript·算法·代码规范
To_OC2 天前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode