LeetCode 494 目标和
题目链接:LeetCode 494 目标和
题目大意:
题解:
回溯
可以使用回溯的方法遍历所有的表达式,回溯过程中维护一个计数器\(count\),当遇到一种表达式的结果等于目标数\(target\)时,将\(count\)的值加\(1\)。遍历完所有的表达式之后,即可得到结果等于目标数\(target\)的表达式的数目。
class Solution {
private:
int cnt = 0;
public:
int findTargetSumWays(vector<int>& nums, int target) {
dfs(nums, target, 0, 0);
return cnt;
}
void dfs(vector<int>& nums, int target, int index, int sum) {
if (index == nums.size()) {
if (sum == target) {
cnt++;
}
} else {
dfs(nums, target, index + 1, sum + nums[index]);
dfs(nums, target, index + 1, sum - nums[index]);
}
}
};
动态规划
参考自LeedCode官方题解
记数组元素和为\(sum\),添加\(-\)号的元素和为\(neg\),则可得到表达式:
\[(sum - neg) - neg = sum - 2 \times neg = target
\]
即
\[neg = \frac{sum - target}{2}
\]
由于数组中都是非负整数,所以\(neg\)也必须是非负整数,因此\(sum - target\)必须是非负偶数,若不符合条件可直接返回\(0\)。
若上式成立,问题转化成在数组\(nums\)中选取若干元素,使得这些元素之和等于\(neg\),计算选取元素的方案数。我们可以使用动态规划的方法求解。
设\(dp[i][j]\)表示在数组\(nums\)的前\(i\)个数中选取元素,使得这些元素之和等于\(j\)的方案数。
状态转移方程:
\[\left\{
\begin{array}{l}
dp[i][j] = dp[i - 1][j],j<nums[i] \\
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]], j \geq nums[i]
\end{array}
\right.
\]
边界条件为\(dp[0][0] = 1\)。
由于\(dp\)的每一行的计算只和上一行有关,因此可以使用滚动数组的方式,去掉\(dp\)的第一个维度,将空间复杂度优化到\(O(neg)\)。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int num : nums) {
sum += num;
}
int temp = sum - target;
if (temp < 0 || temp & 1) {
return 0;
}
temp >>= 1;
vector<int> dp(temp + 1);
dp[0] = 1;
for (int num : nums) {
for (int j = temp; j >= num; --j) {
dp[j] += dp[j - num];
}
}
return dp[temp];
}
};