【问题标题】:Why my recursive code is giving sigsegv error?为什么我的递归代码给出 sigsegv 错误?
【发布时间】:2020-06-03 13:58:16
【问题描述】:

给定一个非负整数数组 arr,您最初位于数组的起始索引处。当您在索引i 时,可以跳转到i + arr[i]i - arr[i],检查是否可以到达任何值为0 的索引。(返回true 或false)。

Input: arr = [4,2,3,0,3,1,2], start = 5
Output: true

说明:索引 5 -> 索引 4 -> 索引 1 -> 索引 3

索引 5 -> 索引 6 -> 索引 4 -> 索引 1 -> 索引 3

注意,任何时候都不能跳出数组。

class Solution 
{
  public:
    bool canReach(vector<int>& arr, int start) 
    {
        if(start<0 || start>=arr.size())
        {
            return false;
        }
        if(arr[start]==0)
        {
            return true;            
        }
        bool x = canReach( arr,  start+arr[start]);
        bool y = canReach( arr,  start-arr[start]);
        return (x||y);
    }
};

【问题讨论】:

  • 对我来说很好。请发布实际上失败的代码。
  • 可能堆栈空间不足。如果第一次返回 true,则不要进行第二次递归调用。你可以这样结束循环。
  • 是的,我需要使用记忆或访问数组打破循环,使其不再访问,谢谢
  • 在跳转到 i + arr[i] 或 i - arr[i] 之前;您检查索引是否超出范围。

标签: c++ segmentation-fault


【解决方案1】:

考虑输入向量为 arr = {1, 1, 1, 1, 1} 和 start = 1 的情况。根据您的代码,在这种情况下,将对函数进行无限次递归调用. 这可以理解为: 如果我们在索引 1 处执行 start - arr[i] 我们到达索引 0。然后如果我们执行 start + arr[i] 我们再次到达索引 1。这会导致对函数的无限次调用。

索引 1 -> 索引 0 -> 索引 1 -> 索引 0 -> 索引 1-> 依此类推。

由于递归使用堆栈,这可能会导致堆栈溢出,从而中止函数执行。

处理这种情况的一种方法是使用 unordered_set 来存储之前访问过的缺陷。如果我们之前访问过一个索引,我们应该简单地返回 false,因为它现在无法返回 true。 这是您可以尝试的实现:

unordered_set<int> s;
bool canReach(vector<int>& arr, int start) {

    if(start<0 || start>=arr.size() || (s.find(start) != s.end()))
        return false;
    if(arr[start]==0)
        return true;            
    s.insert(start);
    bool x = canReach( arr,  start+arr[start]);
    bool y = canReach( arr,  start-arr[start]);
    return (x||y);
}

它应该可以工作。

【讨论】:

  • unordered_set 太过分了。我们知道访问的索引将在 0 和 size(arr) 之间。因此,使用相同索引的简单标志向量就足够了。此外,由于几个原因,拥有一个全局状态变量是有问题的,即它只在第一次调用时起作用。但它也不是线程安全的,等等。更好的方法是 2 个函数,第一个创建一个局部向量(适当的大小),然后调用递归函数,返回其结果。递归函数不被其他任何人调用,并在访问 v[i] 时将向量元素 i 设置为 true。
猜你喜欢
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
相关资源
最近更新 更多