CPP-SCNUOJ-Problem P18. [算法课回溯]目标和,第三刷方法相对简洁一点

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值