【问题标题】:Debugging JS Recursion?调试 JS 递归?
【发布时间】:2022-01-11 10:35:39
【问题描述】:

我正在尝试自己学习递归,并且遇到了一个练习,要求:“编写一个递归函数来确定数组是否为回文,其中数组及其大小作为参数给出。如果返回 1 a[] 是回文,否则为 0。”

我已经尝试了很多东西,但我的代码仍然无法正常工作。我正在访问最后一段代码中的 console.log 检查,但 x、y 和 stepsLeft 变量似乎没有更新。 (警告:)因此,代码是一个未闭合的循环,并且超出了最大调用堆栈大小或代码无限递归。帮忙修一下?

function isPalindrome(arr, size) {
    var stepsLeft;
    var x;
    var y;
    // initialize variables that will change in subsequent calls
    if (stepsLeft === undefined) {
        var hold = size / 2;
        stepsLeft = Math.floor(hold);
        x = 0;
        y = size - 1;
    }

    logged = console.log(stepsLeft);

    //base case: if you go through all steps towards the center and     everything matches, return true
    if (stepsLeft === 0) {
        return 1;
    }

    //recursion cases
    if (arr[x] !== arr[y]) {
        // if the x and y EVER don't match, return false. 
        return 0;
    }

    //increase the x and decrease the y, and check again
    x++;
    y--;
    stepsLeft--;
    console.log("here");
    return isPalindrome(arr, size);
}

【问题讨论】:

  • 传递给isPalindrome的参数(arrsize)实际上从未改变,因此每次调用isPalindrome时,它的运行方式完全相同。为了使递归工作,您需要解决部分问题,然后调用 isPalindrome 处理较小的剩余问题。

标签: javascript debugging recursion


【解决方案1】:

我试图调试递归也是 JavaScript,并认为这可能会帮助任何仍在为调试方法苦苦挣扎的人。

任务:我有一个目标整数s, 7,我需要对从根到叶路径的顶点值求和,其中总和等于目标。

基本上,给定一个简单的二叉树输入:

t = {
    "value": 4,
    "left": {
        "value": 1,
        "left": {
            "value": -2,
            "left": null,
            "right": {
                "value": 3,
                "left": null,
                "right": null
            }
        },
        "right": null
    },
    "right": {
        "value": 3,
        "left": {
            "value": 1,
            "left": null,
            "right": null
        },
        "right": {
            "value": 2,
            "left": {
                "value": -2,
                "left": null,
                "right": null
            },
            "right": {
                "value": -3,
                "left": null,
                "right": null
            }
        }
    }
}

其中,树看起来像:

      4
     / \
    1   3
   /   / \
  -2  1   2
    \    / \
     3  -2 -3

所以,在我们的例子中,答案是: 路径 4 -> 3 -> 2 -> -2 给我们 7。

我的功能:

function solution(t, s, depth = 0, direction = 'root: ') {
    if (t === null) {
        return false
    }
    
    if (isLeaf(t)) {
        console.log("-----------------")
        print(direction, t.value, " in ", depth)
        console.log("=================")
    } else {
        print(direction, t.value, " in ", depth)
    }
    
    s -= t.value;
    
    if (s == 0 && isLeaf(t)) {
        return true
    }
    
    let left = solution(t.left, s, depth + 1, direction = "left-child: ");
    let right = solution(t.right, s, depth + 1, direction = "right-child: ");
    console.log("-> node " + t.value + " has been visited.")
    return left || right
}

然后,如果有解决方案,则返回 true,否则返回 false。

尝试阅读控制台日志并理解它。不应该太复杂。

【讨论】:

    【解决方案2】:

    你可以更简单地实现它。

    开始考虑最小的arr,然后增加它的长度:

    1. 我们知道任何单项数组回文,所以我们已经可以保留size == 1 >> 1
    2. 除了第一种情况,arr 的长度是奇数还是偶数都没有关系,所以我们还可以注意到,对于 2 或 3 个项目,那么 arr[0] === arr[size - 1] >> 1
    3. 结合前面的两个规则,对于最多 3 个项目的 arr,我们可以简单地写成 return (size == 1 || arr[0] == arr[size - 1]) ? 1 : 0;
    4. 现在我们确定这些减少的长度,如果我们将长度增加 2(在 arr 的开头和结尾添加一个项目),我们观察到规则 #2 继续适用于新添加的第一个和最后一个项目

    所以现在可以使用递归了,像这样:

    isPalindrome = function(arr, size) {
      return size > 3 ? isPalindrome(arr.slice(1, -1), size - 2) :
        (size == 1 || arr[0] == arr[size - 1]) ? 1 :
          0
    }
    

    最后一点,我们观察到,只要有超过 3 个项目,上述函数就不会关心第一个和最后一个项目。 如果这些极端项不匹配,我们必须查看它们并立即返回 0,所以它变成:

    isPalindrome = function(arr, size) {
      return arr[0] != arr[size - 1] ? 0 :
        size > 3 ? isPalindrome(arr.slice(1, -1), size - 2) :
          (size == 1 || arr[0] == arr[size - 1]) ? 1 :
            0
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-04
      • 2018-05-08
      • 1970-01-01
      • 1970-01-01
      • 2019-01-19
      • 1970-01-01
      相关资源
      最近更新 更多