为什么静态成员变量不适用于递归方法中的保留值?

时间:2016-11-09 02:22:03

标签: java algorithm recursion pass-by-value

当我尝试解决树问题时,"左叶的总和"在LeetCode OJ上,我观察到如下问题:

给定一个示例树,只有两个左侧离开节点为8和9,期望答案为17,完整树可以参考下面的主要方法。

我首先写的错误答案是使用静态成员变量" sum"存储当前递归的结果并作为参数传递到下一个递归。但是如下面的代码,它将始终返回0。

public class Solution {
   public TreeNode root;

   private static class TreeNode {
      private String val;
      private TreeNode left, right;
      public TreeNode(String x) {
         this.val = x;
      }
   }

   public static int sum = 0;
   public static int sumOfLeftLeaves(TreeNode root) {
      if(root == null) {
         return 0;
      }

      sumOfLeftLeavesRec(root, false, sum);
      return sum;
   }

   public static void sumOfLeftLeavesRec(TreeNode x, boolean isLeft, int sum) {
      if(x == null) {
          return;
      }

      if(x.left == null && x.right == null && isLeft) {
          sum += Integer.valueOf(x.val);
      }

      sumOfLeftLeavesRec(x.left, true, sum);
      // As debug model check, if just use static memeber variable sum could not
      // keep the value when return from deepest recursion, e.g when return from
      // node 8, the sum should be 8 and pass into new recursion on node 6(which
      // return from recursion of node 8), but real situation is sum will change
      // back to 0.
      sumOfLeftLeavesRec(x.right, false, sum);
   }

   public static void main(String[] args) {
     /*
      * The tree used for test
      *        1
      *      /   \
      *     2     3
      *    / \   /
      *   6   5 9
      *  /
      * 8
     */
     Solution s = new Solution();
     s.root = new TreeNode("1");
     s.root.left = new TreeNode("2");
     s.root.right = new TreeNode("3");
     s.root.left.left = new TreeNode("6");
     s.root.left.right = new TreeNode("5");
     s.root.left.left.left = new TreeNode("8");
     s.root.right.left = new TreeNode("9");

     int result = sumOfLeftLeaves(s.root);
     System.out.println(result);
   }
}

我在这个site第二个解决方案Java版本上观察到的正确答案。这产生了一个新的课程" Summ"并使用其成员变量" sum"存储并将结果传递给下一个递归,并且当我测试它工作正常(下面的代码)。主要方法和样本树是相同的。

public class Solution {
   private class Accumulator{
      int sum = 0;
   }

   public int sumOfLeftLeaves(TreeNode root) {
      if(root == null) {
          return 0;
      }

      Accumulator accumulator = new Accumulator();

      sumOfLeftLeavesRec(root, false, accumulator);
      return accumulator.sum;
   }

   /* Pass in a sum variable as an accumulator */
   public void sumOfLeftLeavesRec(TreeNode x, boolean isLeft, Accumulator accumulator) {
      if(x == null) {
          return;
      }

      if(x.left == null && x.right == null && isLeft) {
          accumulator.sum += x.val;
      }

      sumOfLeftLeavesRec(x.left, true, accumulator);
      sumOfLeftLeavesRec(x.right, false, accumulator);
   }
}

问题是为什么静态成员变量在这种情况下不起作用,为什么要创建一个新的嵌套类作为" Accumulator"可用于记录和传递"总和"结果成功了?从机制上讲,关键点是什么?感谢

2 个答案:

答案 0 :(得分:1)

  

为什么静态成员变量不适用于递归方法中的保留值?

事实上,问题不在于sum是静态的(虽然static sum 是一个坏主意......)

问题在于此代码:

public static void sumOfLeftLeavesRec(TreeNode x, boolean isLeft, int sum) {
    if(x == null) {
        return;
    }

    if(x.left == null && x.right == null && isLeft) {
        sum += Integer.valueOf(x.val);
    }
    ...
 }

sum变量不是静态的。这是一个局部变量。所以你正在做的是在每个sumOfLeftLeavesRec调用结束时计算局部变量中的部分和然后将其丢弃

您需要回到原始问题陈述,并弄清楚信息需要如何在递归调用之间流动。

提示:设计简单递归算法的 normal 方法是将信息作为调用参数传递,并将其作为调用结果返回。这应该在这里工作。

答案 1 :(得分:0)

在你的情况下,你创建整数变量sum它是原始的和不可变的。 您将此不可变变量作为参数传递,因此静态变量sum不会更新,因此请删除参数sum。  试试这个。

    public class Solution {
  public TreeNode root;

  private static class TreeNode {
    private String val;
    private TreeNode left, right;

    public TreeNode(String x) {
      this.val = x;
    }
  }

  public static int sum = 0;

  public static int sumOfLeftLeaves(TreeNode root) {
    if (root == null) {
      return 0;
    }

    sumOfLeftLeavesRec(root, false);
    return sum;
  }

  public static void sumOfLeftLeavesRec(TreeNode x, boolean isLeft) {
    if (x == null) {
      return;
    }

    if (x.left == null && x.right == null && isLeft) {
      sum += Integer.valueOf(x.val);
    }

    sumOfLeftLeavesRec(x.left, true);
    // As debug model check, if just use static memeber variable sum could not
    // keep the value when return from deepest recursion, e.g when return from
    // node 8, the sum should be 8 and pass into new recursion on node 6(which
    // return from recursion of node 8), but real situation is sum will change
    // back to 0.
    sumOfLeftLeavesRec(x.right, false);
  }

  public static void main(String[] args) {
     /*
      * The tree used for test
      *        1
      *      /   \
      *     2     3
      *    / \   /
      *   6   5 9
      *  /
      * 8
     */
    Solution s = new Solution();
    s.root = new TreeNode("1");
    s.root.left = new TreeNode("2");
    s.root.right = new TreeNode("3");
    s.root.left.left = new TreeNode("6");
    s.root.left.right = new TreeNode("5");
    s.root.left.left.left = new TreeNode("8");
    s.root.right.left = new TreeNode("9");

    int result = sumOfLeftLeaves(s.root);
    System.out.println(result);
  }
}