回溯
1.全局变量解法
先画出决策树,然后分析,每一次到达叶子节点需要判断是否为目标值,然后返回上一级时需要完成恢复现场,左边递归玩恢复到右边也需要恢复现场
然后寻找递归出口,发现需要标记层数才可以完成dfs,所以在函数头的构造中要加入pos
class Solution {
int ret;
int path;
int aim;
public int findTargetSumWays(int[] nums, int target) {
aim = target;
ret = 0;
dfs(nums,0);
return ret;
}
public void dfs(int[] nums,int pos){
if(pos == nums.length){
if(path == aim){
ret++;
}
return;
}
path += nums[pos];
dfs(nums,pos + 1);
path -= nums[pos] * 2;
dfs(nums,pos + 1);
path += nums[pos];
}
}
2.局部变量解法
使用局部变量会更加简洁,思路和上一个一样一样要画出决策树,不同的是函数本身会帮你存储原来的内容,不需要手动进行回溯
class Solution {
int ret;
int aim;
public int findTargetSumWays(int[] nums, int target) {
aim = target;
ret = 0;
dfs(nums,0,0);
return ret;
}
public void dfs(int[] nums,int pos,int path){
if(pos == nums.length){
if(path == aim){
ret++;
}
return;
}
dfs(nums,pos + 1,path + nums[pos]);
dfs(nums,pos + 1,path - nums[pos]);
}
}
总结
在这题中,局部变量的使用会比全局变量快更简洁,但存储数组那些优先选择全局变量,存储单一整数就使用局部变量来存储
动态规划
这是本题的最优解法
开始需要将它转化为可以使用动态规划的模型
然后开始找状态转移方程
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int n = nums.length;
int sum = 0;
for(int x : nums){
sum += x;
}
int aim = (sum + target) / 2;
if(aim < 0 || (sum + target) % 2 == 1){
return 0;
}
int[][] dp = new int[n + 1][aim + 1];
dp[0][0] = 1;
for(int i = 1;i <= n;i++){
for(int j = 0;j <= aim;j++){
dp[i][j] += dp[i - 1][j];
if(j >= nums[i - 1]){
dp[i][j] += dp[i-1][j - nums[i - 1]];
}
}
}
return dp[n][aim];
}
}