C++ 递归函数工作,但无法记忆

C++ 递归函数工作,但无法记忆,c++,algorithm,recursion,dynamic-programming,memoization,C++,Algorithm,Recursion,Dynamic Programming,Memoization,我正在LeetCode.com上解决这个动态规划问题: 给您一个非负整数列表,a1、a2、…、an和目标S。现在您有2个符号+和-。对于每个整数,您应该从+和-中选择一个作为其新符号。了解分配符号使整数和等于目标S的方法。 对于输入[1,1,1,1,1]和S=3,输出应为5 制约因素包括: 给定数组的长度为正,不会超过20 给定数组中的元素之和将不超过1000 您的输出答案保证适合32位整数。 我想出了以下代码: 类解决方案{ 公众: 向量n; int-s; int-helper(向量和dp、i

我正在LeetCode.com上解决这个动态规划问题:

给您一个非负整数列表,a1、a2、…、an和目标S。现在您有2个符号+和-。对于每个整数,您应该从+和-中选择一个作为其新符号。了解分配符号使整数和等于目标S的方法。 对于输入
[1,1,1,1,1]
和S=
3
,输出应为
5

制约因素包括:

给定数组的长度为正,不会超过20
给定数组中的元素之和将不超过1000
您的输出答案保证适合32位整数。

我想出了以下代码:

类解决方案{
公众:
向量n;
int-s;
int-helper(向量和dp、int-sum、int-startIndex){
如果(startIndex==n.size()){
如果(sum==s)返回dp[startIndex][sum]=1;
否则返回dp[startIndex][sum]=0;
}
如果(dp[startIndex][sum]!=-1)返回dp[startIndex][sum];
返回dp[startIndex][sum]=helper(dp,sum+n[startIndex],startIndex+1)+
助手(dp,sum-n[startIndex],startIndex+1);
}
int findTargetSumWays(向量和nums,int S){
n=nums;
s=s;
载体dp(21,载体(1001,-1));
返回帮助器(dp,0,0);
}
};
如果不使用
dp
表进行记忆,代码在所有139个测试用例上都可以正常运行(
139/139测试用例通过,但时间太长。
),但明显超过了时间限制。现在,在如上所述的记忆中,我得到了一个运行时错误:

运行时错误:向0x6201000008D00添加无符号偏移量溢出到0x6201000008CFC(stl_vector.h) 摘要:UndefinedBehaviorSanitizer:undefined behavior/usr/bin/./lib/gcc/x86_64-linux-gnu/8/../../../../../../include/c++/8/bits/stl_vector.h:933:34


我做错了什么?

可以使用动态规划优化问题,将
当前索引
总和
作为状态

您的解决方案的问题是,
Sum
本身可能是一个非常大的数字或负数,访问如此大的索引会导致运行时错误,因为在此类平台(沙盒环境)上提供的内存有限。最好的方法是使用地图。

检查以下已接受Leetcode判断的解决方案:

typedef long long int LL;

class Solution {
public:

    std::map<pair<LL, LL>, LL> mp;

    LL find(int currentIndex, int len, LL S, std::vector<int>& nums){


        if(mp.find(make_pair(currentIndex, S)) != mp.end()){
            return mp[make_pair(currentIndex, S)];
        }

        if(S!=0 and currentIndex >= len){
            return 0;
        }


        if(S==0 && currentIndex==len){
            return 1;
        }


        LL ans = find(currentIndex+1, len, S-nums[currentIndex], nums) + find(currentIndex+1, len, S+nums[currentIndex], nums);

        mp[make_pair(currentIndex, S)] = ans;

        return mp[make_pair(currentIndex, S)];

    }

    int findTargetSumWays(vector<int>& nums, int S) {


        return find(0, nums.size(), S, nums);

    }
};
typedef long long int LL;
类解决方案{
公众:
std::map-mp;
LL find(int currentIndex、int len、LL S、std::vector和nums){
if(mp.find(make_pair(currentIndex,S))!=mp.end(){
返回mp[make_pair(currentIndex,S)];
}
如果(S!=0且currentIndex>=len){
返回0;
}
如果(S==0&¤tIndex==len){
返回1;
}
LL ans=find(currentIndex+1,len,S-nums[currentIndex],nums)+find(currentIndex+1,len,S+nums[currentIndex],nums);
mp[配对(当前索引,S)]=ans;
返回mp[make_pair(currentIndex,S)];
}
int findTargetSumWays(向量和nums,int S){
返回find(0,nums.size(),S,nums);
}
};

与动态编程类似,可能更清晰、更容易理解:

#include <vector>
#include <numeric>

class Solution {
public:
    inline int findTargetSumWays(const std::vector<int> &nums, const int target) {
        int copy_target = target;
        std::vector<int> copy_nums = nums;
        int sum = std::accumulate(copy_nums.begin(), copy_nums.end(), 0);

        if (sum < copy_target || (sum + copy_target) & 1) {
            return 0;
        }

        return get_subarray_sum(copy_nums, (sum + copy_target) >> 1);

    }

private:
    static inline int get_subarray_sum(const std::vector<int> &nums, const int target) {
        std::vector<int> symbols_assign(target + 1, 0);
        symbols_assign[0] = 1;

        for (int num : nums)
            for (int index = target; index > num - 1; index--) {
                symbols_assign[index] += symbols_assign[index - num];
            }

        return symbols_assign[target];
    }
};
#包括
#包括
类解决方案{
公众:
内联int findTargetSumWays(const std::vector&nums,const int target){
int copy_target=目标;
标准::向量拷贝_nums=nums;
int sum=std::累加(copy_nums.begin(),copy_nums.end(),0);
if(sum>1);
}
私人:
静态内联int get_subarray_sum(const std::vector&nums,const int target){
std::向量符号分配(目标+1,0);
符号分配[0]=1;
for(int-num:nums)
对于(int index=target;index>num-1;index--){
符号分配[index]+=符号分配[index-num];
}
返回符号_分配[目标];
}
};

工具书类
  • 有关其他详细信息,请参见。这里有很多公认的解决方案,有各种解释和解释,有高效的算法,还有渐近/复杂性分析

因为您的总和可以是负数,并且您正在使用它进行索引。为了索引的目的,将总和移动
1000
,这会有所帮助。啊,说得好。错过了。你能详细说明一下,为了索引的目的,将总和移动1000会有帮助吗?好的,你的总和的值可以在[-10001000]范围内。通过向其添加1000,您将拥有范围[0,2000],可用于索引。@J.Doe对向量的
at()
进行一些调用,而不是使用
[]
将向您显示代码出现问题的位置。通常,如果您编写了一个不带数组或指针的
向量
唯一解决方案,那么这样的运行时错误几乎总是表示访问超出了范围。然后重写代码,使用
at()
查看越界发生的位置。然后,您将得到一个更容易诊断的
std::out\u of_range
异常,而不是运行时错误。明白了!谢谢,德米特里!如果你能把你的评论变成一个答案,我很乐意接受。