如何避免在递归中使用全局/类级别变量?
Posted
技术标签:
【中文标题】如何避免在递归中使用全局/类级别变量?【英文标题】:How to avoid using global/class level variables in recursion? 【发布时间】:2022-01-22 08:33:45 【问题描述】:如果方法继续使用/更新全局变量,递归解决方案变得容易,但当您需要将该变量传递到递归堆栈时,它变得复杂。
以下是leetcode问题250. Count Univalue Subtrees的递归解决方案(java)。
您可以参考问题以获得更好的理解。我的解决方案工作得很好。我想避免使用全局变量。
问题陈述:
给定二叉树的根,返回单值子树的数量。 单值子树意味着子树的所有节点都具有相同的值。
示例 1输入:root = [5,1,5,5,5,null,5]
输出:4
输入:root = []
输出:0
输入:root = [5,5,5,5,5,null,5]
输出:6
/**
* Definition for a binary tree node.
* public class TreeNode
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode()
* TreeNode(int val) this.val = val;
* TreeNode(int val, TreeNode left, TreeNode right)
* this.val = val;
* this.left = left;
* this.right = right;
*
*
*/
class Solution
int uniCount; // class level variable to keep the count of uni-valued tree/sub-tree
public int countUnivalSubtrees(TreeNode root)
uniCount = 0;
recurseAndUpdate(root);
return uniCount;
private boolean recurseAndUpdate(TreeNode root)
if (root == null)
return true;
if (root.left == null && root.right == null) // If root is a leaf node
uniCount++;
return true;
else if (root.left == null && root.right != null) // If root has only right child
boolean currRes = root.val == root.right.val;
boolean rightRes = recurseAndUpdate(root.right);
if (currRes && rightRes)
uniCount++;
return true;
else if (root.left != null && root.right == null) // If root has only left child
boolean currRes = root.val == root.left.val;
boolean leftRes = recurseAndUpdate(root.left);
if (currRes && leftRes)
uniCount++;
return true;
else // If root have both the left & right child
boolean currRes = root.val == root.left.val && root.val == root.right.val;
boolean leftRes = recurseAndUpdate(root.left);
boolean rightRes = recurseAndUpdate(root.right);
if (currRes && leftRes && rightRes)
uniCount++;
return true;
return false;
在上述递归函数 recurseAndUpdate(TreeNode root)
中,类变量 uniCount
正在根据某些约束进行更新。
我怎样才能摆脱使用这个全局变量并想出像 recurseAndUpdate(TreeNode root, int uniCount)
这样的解决方案?对于这种倾向于在嵌套递归调用中传递一些值的递归逻辑,如何推导出方法?
【问题讨论】:
在参数列表中传递您需要的内容。永远不要使用全局状态。 是的,这就是我想要做的。你能想出一个解决方案,或者编辑上面的那个。 @nathan-hughes 我已将链接添加到实际问题。看看这是否有意义。 【参考方案1】:您的递归函数当前返回一个布尔值来指示子树是否是单调的。您可以改为让它返回该子树中单调子树的数量,并且当它本身不是单调子树时使该数字负。
这样你就有递归函数在一个包中返回两个信息:
非负数表示子树是单调的(或空的)并且由那么多节点组成。
负数表示子树不是单调的,并且有那么多(绝对值)单调的子树。
调整您的代码以使其像那样工作并不难。然后,您的包装函数只需返回来自递归树顶部调用的值的绝对值。
我尝试过,但我确实减少了一些代码——避免代码重复:
public int countUnivalSubtrees(TreeNode root)
return Math.abs(recurseAndUpdate(root));
private int recurseAndUpdate(TreeNode root)
if (root == null)
return 0;
boolean current = (root.left == null || root.val == root.left.val) &&
(root.right == null || root.val == root.right.val);
int leftRes = recurseAndUpdate(root.left);
int rightRes = recurseAndUpdate(root.right);
return leftRes < 0 || rightRes < 0 || !current
? -Math.abs(leftRes) - Math.abs(rightRes)
: leftRes + rightRes + 1;
【讨论】:
【参考方案2】:您可以先为您的计数器定义一个类,然后轻松地将其传递给递归函数。例如如下:
// define a class as a wrapper
class RecursiveCounter
int value;
public RecursiveCounter()
value = 0;
// modify the current solution class as follows
// remove the global variable
private boolean recurseAndUpdate(TreeNode root, RecursiveCounter uniCount)
// replace all uniCount to uniCount.value
// Also, pass the same uniCount variable to all recursive calls
// ...
public int countUnivalSubtrees(TreeNode root)
RecursiveCounter uniCount;
recurseAndUpdate(root, unitCount);
return uniCount.value;
【讨论】:
这在我们希望保持递归整洁和干净的方式中非常有用。谢谢以上是关于如何避免在递归中使用全局/类级别变量?的主要内容,如果未能解决你的问题,请参考以下文章
计算机系统篇之链接(11):为什么要避免在 C/C++ 中使用全局变量