动态图解算法面试题之栈的压入、弹出顺序

中间有动态图展示过程。

 

01 题目描述

输入两个整数序列,第一个序列表示栈的压入顺序,第二个表示栈的弹出顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。

例如:序列1,2,3,4,5是栈的压入顺序,4,5,3,2,1是该栈的弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。 

02 解释

1.入栈顺序 1,2,3,4,5。

出栈顺序,4,5,3,2,1

解题过程,我们需要用一个辅助栈,按照出栈顺序把入栈数值压入弹出一遍,对比弹出顺序是否与出栈相等

(1)出栈元素4,那么4之前所有的入栈元素1,2,3,4都已经入辅助栈。(1,2,3不先入栈,4怎么入栈,也没法出栈了),辅助栈结果,1,2,3,4。对比辅助栈4和出栈元素4相等弹出。

入栈顺序 1,2,3,4,5。

出栈顺序4,5,3,2,1

辅助栈元素,1,2,3,弹出栈顶元素4

(2)出栈元素5,辅助栈中栈顶元素不是5,所以从入栈序列中把5之前的元素都入栈,直到遇到5

入栈顺序 1,2,3,45

出栈顺序 45,3,2,1

辅助栈,1,2,3,5,弹出对应栈顶元素5

(3)出栈顺序3 与辅助栈顶元素3,对比相等,弹出栈顶元素3.

入栈顺序 1,2,3,4

<think>我们有一个二叉树,需要计算所有从根节点到叶子节点的路径和。每条路径代表一个数字,例如路径1->2->3表示数字123,我们需要求所有这样的数字之和。根据引用[3],有两种方法:递归(深度优先搜索DFS)和非递归(使用)。我们将分别介绍这两种方法。方法一:递归(DFS)思路:1.从根节点开始递归遍历,每次递归时将当前路径表示的数字传递下去(即父节点传递的数字乘以10再加上当前节点的值)。2.当遇到叶子节点(左右子节点都为空)时,将当前计算得到的数字加到总和中。3.递归遍历左子树和右子树。方法二:非递归(使用)思路:1.使用两个:一个存储节点(nodeStack),另一个存储从根节点到该节点路径所表示的数字(numStack)。2.初始时,将根节点和根节点的值分别两个。3.当不为空时,弹出顶节点和对应的数字。-如果该节点是叶子节点,则将数字加总和。-否则,如果存在左子节点,则计算左子节点对应的数字(当前数字乘以10再加上左子节点的值),并将左子节点和新的数字。-同样,如果存在右子节点,则计算右子节点对应的数字,并将右子节点和新的数字。注意:节点值在0-9之间,且树节点数在1到1000之间,深度不超过10。下面分别用伪代码和具体代码(以Java为例)说明。递归方法伪代码:functiondfs(TreeNodenode,intcurrentSum){ifnodeisnull,return0;currentSum=currentSum*10+node.val;ifnode.leftisnullandnode.rightisnull:returncurrentSum;else:returndfs(node.left,currentSum)+dfs(node.right,currentSum);}但是注意,上面的伪代码中,如果节点为空,我们返回0,因为空节点不贡献值。而叶子节点返回当前计算得到的值(currentSum),非叶子节点则返回左右子树路径和之和。然而,实际递归中,我们需要注意:如果当前节点为空,则直接返回0;如果当前节点是叶子节点,则返回currentSum;如果不是叶子节点,则递归计算左右子树。非递归方法伪代码:intsum=0;Stack<TreeNode>nodeStack=newStack<>();Stack<Integer>numStack=newStack<>();nodeStack.push(root);numStack.push(root.val);while(!nodeStack.empty()){TreeNodenode=nodeStack.pop();intnum=numStack.pop();if(node.left==null&&node.right==null){sum+=num;}if(node.right!=null){nodeStack.push(node.right);numStack.push(num*10+node.right.val);}if(node.left!=null){nodeStack.push(node.left);numStack.push(num*10+node.left.val);}}returnsum;注意:非递归方法中,我们先处理左子树还是右子树?由于是后进先出,所以为了先处理左子树,我们应该先右子树再左子树(这样左子树后,就会先被弹出处理)。但也可以按任意顺序,因为最终每条路径都会计算到。不过,如果希望顺序和先序遍历一致,可以先右子树再左子树。现在,我们以引用[3]中的图为例,用代码实现。下面给出Java代码实现:递归方法:```javapublicintsumNumbers(TreeNoderoot){returndfs(root,0);}privateintdfs(TreeNodenode,intcurrentSum){if(node==null){return0;}currentSum=currentSum*10+node.val;if(node.left==null&&node.right==null){returncurrentSum;}returndfs(node.left,currentSum)+dfs(node.right,currentSum);}```非递归方法:```javapublicintsumNumbers(TreeNoderoot){if(root==null){return0;}intsum=0;Stack<TreeNode>nodeStack=newStack<>();Stack<Integer>numStack=newStack<>();nodeStack.push(root);numStack.push(root.val);while(!nodeStack.isEmpty()){TreeNodenode=nodeStack.pop();intnum=numStack.pop();if(node.left==null&&node.right==null){sum+=num;}//先右后左,保证左子树先被处理(因为是LIFO)if(node.right!=null){nodeStack.push(node.right);numStack.push(num*10+node.right.val);}if(node.left!=null){nodeStack.push(node.left);numStack.push(num*10+node.left.val);}}returnsum;}```注意:以上代码假设TreeNode的定义为:```javaclassTreeNode{intval;TreeNodeleft;TreeNoderight;TreeNode(){}TreeNode(intval){this.val=val;}TreeNode(intval,TreeNodeleft,TreeNoderight){this.val=val;this.left=left;this.right=right;}}```以上两种方法都可以决该问题。递归方法更简洁,非递归方法避免了递归调用的开销(但深度不大,所以递归也可以)。根据引用[2]和引用[3]的提示,我们还可以参考打印路径的方法,但本题不需要打印路径,只需要累加路径表示的数字。此外,引用[4]提到了一个数组存储的二叉树,但本题并没有要求用数组存储,所以按照常规的二叉树节点结构处理即可。如果用户需要的是数组存储的二叉树,那么我们可以先构建二叉树,然后再用上述方法。但题目要求的是常规二叉树。因此,我们提供了递归和非递归两种方法。如果用户需要其他语言的实现,可以进一步询问。相关问题:1.如果要求输出每条路径的数字而不仅仅是总和,应如何修改?2.如果二叉树节点值超出0-9的范围(比如两位数),上述方法还适用吗?需要如何调整?3.如何用广度优先搜索(BFS)实现该问题?</think>### 二叉树路径总和计算 在二叉树中计算从根节点到叶子节点的路径总和,本质是将每条路径上的节点值组合成一个数字(例如路径 `1→2→3` 表示为 `123`),并求所有路径数字之和。以下是两种核心方法: --- #### **方法1:递归(深度优先搜索 - DFS)** **核心思想**:在递归遍历中传递路径当前累积值,遇到叶子节点时累加总和。 ```java public int sumNumbers(TreeNode root) { return dfs(root, 0); } private int dfs(TreeNode node, int currentSum) { if (node == null) return 0; // 更新当前路径值:父路径×10 + 当前节点值 currentSum = currentSum * 10 + node.val; // 叶子节点:返回当前路径值 if (node.left == null && node.right == null) return currentSum; // 非叶子节点:递归左右子树 return dfs(node.left, currentSum) + dfs(node.right, currentSum); } ``` **时间复杂度**:$O(N)$,每个节点访问一次 **空间复杂度**:$O(H)$,递归深度($H$ 为树高) --- #### **方法2:非递归(迭代)** **核心思想**:用两个分别存储节点和对应的路径值,按深度优先模拟递归过程。 ```java public int sumNumbers(TreeNode root) { if (root == null) return 0; Stack<TreeNode> nodeStack = new Stack<>(); Stack<Integer> numStack = new Stack<>(); nodeStack.push(root); numStack.push(root.val); int totalSum = 0; while (!nodeStack.isEmpty()) { TreeNode node = nodeStack.pop(); int currentNum = numStack.pop(); // 遇到叶子节点:累加路径值 if (node.left == null && node.right == null) { totalSum += currentNum; } // 右子树(先右后左保证处理顺序) if (node.right != null) { nodeStack.push(node.right); numStack.push(currentNum * 10 + node.right.val); } // 左子树 if (node.left != null) { nodeStack.push(node.left); numStack.push(currentNum * 10 + node.left.val); } } return totalSum; } ``` **时间复杂度**:$O(N)$ **空间复杂度**:$O(N)$,存储节点 --- ### **关键说明** 1. **节点值范围**:题目限定节点值为 `0-9`,因此路径组合不会溢出(深度≤10)。 2. **路径定义**:只有当节点是**叶子节点**(左右子树均为空)时才构成完整路径。 3. **二叉树结构**: ```java class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } ``` > **示例**:二叉树 `[1,2,3]`(根1,左2,右3) > - 路径 `1→2` → 数字 `12` > - 路径 `1→3` → 数字 `13` > - 总和 = $12 + 13 = 25$ --- ### 相关问题 1. 如果要求输出所有路径的具体数字(而不仅是总和),如何修改代码?[^2] 2. 当二叉树节点值超过个位数(如两位数)时,上述算法是否仍有效?需要如何调整? 3. 如何用**广度优先搜索(BFS)** 实现路径总和计算?与DFS相比有何优劣?[^3] 4. 若二叉树以数组形式存储(下标 `n` 的子节点在 `2n` 和 `2n+1`),如何计算路径总和?[^4] [^1]: 简单算法 二叉树根节点到叶子节点的所有路径和(java) [^2]: 二叉树根节点到叶子节点路径问题 [^3]: 面试经典算法系列之二叉树9 -- 二叉树求根节点到叶子结点数字之和 [^4]: 给定一个数组存储的二叉树,求根节点到最小叶子节点的路径
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值