Problem P18. [算法课回溯]目标和
给你一个整数数组 nums 和一个整数 target 。
向数组中的每个整数前添加 ‘+’ 或 ‘-’ ,然后串联起所有整数,可以构造一个 表达式 :
例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串联起来得到表达式 “+2-1” 。 返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
提示:
1 <= nums.length <= 20
0 <= nums[i] <= 1000
0 <= sum(nums[i]) <= 1000
-1000 <= target <= 1000
输入
第一行为若干整数代表 nums
第二行为整数 target
输出
一行一个整数代表答案
样例
标准输入
1 1 1 1 1
3
标准输出
5
标准输入
3 4 5 3 3
12
标准输出
3
提示
输出:5 样例一解释:一共有 5 种方法让最终目标和为3
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
解题思路:参考文章1,参考文章2
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
vector<int> nums;//nums容器装输入的数字,但是最后一个数字是‘目标和’,需要pop_back扔掉;
int cnt = 0;//累加达到目标和的计数;
/*
容器nums;idx:指针位置,取nums中的数字,从0出发,不断+1;sum:从0出发,算求和不停+-数字;target:最终目标和
*/
void backtrack(vector<int> &nums, int idx, int sum, int target)
{
//递归算法,先判断终止条件;当idx跑到nums.size()时,终止,判断sum是否=target,来cnt++
if(idx == nums.size())
{
if(sum == target)
{
cnt++;
}
return;
}
backtrack(nums, idx+1, sum+nums[idx], target);//指针移到下一位,加上一个数
backtrack(nums, idx+1, sum-nums[idx], target);//指针移到下一位,减去一个数
}
int main()
{
int n;
while(cin >> n)
{
nums.push_back(n);
}
// cout << "length0=" << nums.size() << endl;
// int m = nums.back();
// cout << "m=" << m << endl;
// nums.pop_back();
// cout << "length1=" << nums.size() << endl;
int target = nums.back();//容器nums最后一个数字是目标和;
nums.pop_back();//把容器nums最后一个数字推出,剩下才是需要加减的数字
backtrack(nums, 0, 0, target);
cout << cnt;
// cout << "Hello world!" << endl;
return 0;
}
自我练习,二刷
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
/*
思路:定义函数f(i,target),表示[0,i]这个范围内目标和为target的方法数
f(i,target)=f(i-1,target-nums[i])+f(i-1,target+nums[i]);
这里从后往前移一位,等于前面的方法和相加
用一个idx来计数,每次移动一位,直到idx=nums.size(),此时得到一种方法,cnt++;
*/
vector<int> nums;//储存数组,最后一个为target,需要推出
int cnt = 0;
// 数组;idx次数;sum当前和;target目标和
void backtrack(vector<int> &nums, int idx, int sum, int target)
{
//递归,截止条件idx=数组长度;当前和=目标和,cnt++;
if(idx == nums.size())
{
if(sum == target)
{
cnt++;
}
//反之,到达不了目标和,这个路线不行,直接结束return;
return;
}
backtrack(nums, idx+1, sum+nums[idx], target);
backtrack(nums, idx+1, sum-nums[idx], target);
}
int main()
{
int x;
while(cin >> x)
{
nums.push_back(x);
}
int target = nums.back();//最后一个为target;
nums.pop_back();//推出最后一个target;
backtrack(nums, 0, 0, target);
cout << cnt;
// cout << "Hello world!" << endl;
return 0;
}
三刷,这个方法最简洁
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int cnt = 0;
vector<int> nums;
void f(vector<int> &nums, int idx, int target)
{
if(idx == nums.size())
{
if(target == 0)
{
cnt++;
}
return;
}
f(nums, idx+1, target-nums[idx]);
f(nums, idx+1, target+nums[idx]);
}
int main()
{
int x;
while(cin >> x)
{
nums.push_back(x);
}
int target = nums.back();
nums.pop_back();
f(nums, 0, target);
cout << cnt;
// cout << "Hello world!" << endl;
return 0;
}