You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归为何无法自动处理变量状态?二叉树递归场景对比

二叉树递归中的状态处理疑问解答

场景一:收集根到叶的所有路径

class Node {
    constructor (val) {
        this.val   = val;
        this.left  = null;
        this.right = null; 
    }
}

const a = new Node('10');
const b = new Node('20');
const c = new Node('30');
const d = new Node('40');
const e = new Node('60');


a.left = b;
a.right = c;
b.left = d;
b.right = e;

function Paths(root){
        let paths = [];
        function traverse(node, path){
            if(!node){
                return;
            }
            path.push(node.val);
            if(node.left ==null && node.right ==null){
                paths.push(path.slice());
            }
            traverse(node.left,path);
            traverse(node.right,path);
            path.pop();
        }
        traverse(root,[]);
        console.log(paths);
        return paths;
    }
    Paths(a);

疑问解答:递归共享path时为何无法自动恢复状态?

因为path是引用类型(数组),递归调用时传递的是同一个数组的引用——所有递归栈中的函数操作的都是内存里的同一个数组实例。

比如遍历路径10→20→40时,path被push成['10','20','40'],处理完叶子节点40后递归返回至节点20,如果不执行path.pop(),数组会保持这个状态。接下来处理节点20的右子节点60时,就会把60push到同一个数组里,变成['10','20','40','60'],这显然不是我们要的10→20→60路径。

所以必须通过path.pop()手动回溯:在离开当前节点时,把节点值从数组中移除,让path恢复到进入该节点前的状态,这样后续处理其他分支时才不会被之前的操作污染。


场景二:判断是否存在和为目标值的根到叶路径

class Node {
    constructor (val) {
        this.val   = val;
        this.left  = null;
        this.right = null; 
    }
}

const a = new Node('1');
const b = new Node('2');
const c = new Node('3');
a.left = b;
a.right = c;


var hasPathSum = function(root, targetSum) {
    if(!root){
        return 0;
    }
    function dfs(node, currsum){
        if(!node){
            return false;
        }
        currsum+=Number(node.val);
        if(node.left ==null && node.right ==null){
            return currsum == targetSum;
        }

        return dfs(node.left,currsum) || 
        dfs(node.right,currsum);
    }
    return dfs(root, 0);
};

let targetSum =31;
console.log(hasPathSum(a, targetSum));

疑问解答:为何无需回溯操作?

因为currsum是基本类型(数字),在JavaScript中基本类型是按值传递的:每次递归调用时,会把currsum的当前值复制一份,作为新的变量传给下一层递归函数。

比如在节点1时currsum是1,调用左子节点2时,会创建一个新的currsum变量,值为1+2=3,这个新变量和上层的currsum=1完全独立;同理,处理右子节点3时,用的还是上层的currsum=1,计算后得到新的currsum=4。每个递归分支的currsum都是各自独立的副本,不会互相干扰,因此不需要手动回溯恢复状态。


内容的提问来源于stack exchange,提问作者amit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:34:49