计算二叉树中所有节点的深度

huangapple go评论135阅读模式
英文:

Calculating node depths of all nodes in a Binary Tree

问题

以下是翻译好的内容:

我正在尝试解决AlgoExpert的Node Depths问题。这个问题要求你计算给定二叉树中所有节点深度的总和。例如,给定以下树 -

          1
       /     \
      2       3
    /   \   /   \
   4     5 6     7
 /   \
8     9

总和应为16。

我写了一个递归解决方案,我认为是正确的,但有趣的是,只有第一个测试通过,而其余测试用例失败了。这是我的解决方案 -

    import java.util.*;
    
    class Program {
    
      // 用于保存最终总和的静态变量
      private static int finalSum = 0;

      public static int nodeDepths(BinaryTree root) {
            // 在这里编写你的代码。
    		int runningSum = 0;
    		depthHelper(root.left, runningSum);
    		depthHelper(root.right, runningSum);
            return finalSum;
      }
    	
    	private static void depthHelper(BinaryTree node, int runningSum) {
    		if(node == null) return;
    		runningSum++;
    		finalSum += runningSum;
    		depthHelper(node.left, runningSum); 
    		depthHelper(node.right, runningSum);
    	}
    
      static class BinaryTree {
        int value;
        BinaryTree left;
        BinaryTree right;
    
        public BinaryTree(int value) {
          this.value = value;
          left = null;
          right = null;
        }
      }
    }

算法本身相当简单。

有一个runningSum变量(初始化为-1以考虑根节点),每次访问一个新节点(即从其父节点下降一级)时,我都会加1。这个runningSum变量的值在每次递归调用时都会添加到finalSum变量中。

例如,在节点2处,runningSum1,这被添加到finalSum,其值为0。现在finalSum变成了1。节点3同样,之后finalSum变成了2。在节点4runningSum变为2finalSum变为4

第一个测试用例通过了,我得到了这个消息 -

计算二叉树中所有节点的深度

但是,随后的所有测试都失败了。我认为可能发生的情况是 - 上一个测试用例执行的输出没有被清除,以某种方式被添加到当前测试用例执行的结果中。

我认为这可能是原因的原因如下 -

 1. 测试用例2 - 我们的代码输出 - 0,你的代码输出 - 16
 2. 测试用例3 - 我们的代码输出 - 1,你的代码输出 - 17
 3. 测试用例4 - 我们的代码输出 - 2,你的代码输出 - 19
 4. 测试用例5 - 我们的代码输出 - 4,你的代码输出 - 23
 5. 测试用例6 - 我们的代码输出 - 21,你的代码输出 - 44
 6. 测试用例7 - 我们的代码输出 - 42,你的代码输出 - 86

请注意,先前执行的结果没有被清除,并被添加到后续执行的“你的代码输出”中。例如,在第二个测试用例中,“你的代码输出”结果显示为16,实际上是第一个测试用例的结果。

这是因为代码中使用了全局的static变量吗?但是我以前在LeetCode上多次使用过相同的方法,那里运行得很好。

或者我的算法中有不同的错误?

PS - 我知道在这里使用屏幕截图是不被允许的,但这可能是一个特定于平台的问题,所以我不得不使用它。

英文:

I'm trying to solve the Node Depths question from Algoexpert. The problem requires you to calculate the sum of depths of all the nodes in a given binary tree. For example, given this tree -

          1
       /     \
      2       3
    /   \   /   \
   4     5 6     7
 /   \
8     9

the sum should be 16.

I wrote a recursive solution to it, which I think is correct, but interestingly enough, only the first test passes, while the remaining test cases fail. Here is my solution-

import java.util.*;

class Program {

  // static variable to hold the final sum
  private static int finalSum = 0;

  public static int nodeDepths(BinaryTree root) {
        // Write your code here.
		int runningSum = 0;
		depthHelper(root.left, runningSum);
		depthHelper(root.right, runningSum);
        return finalSum;
  }
	
	private static void depthHelper(BinaryTree node, int runningSum) {
		if(node == null) return;
		runningSum++;
		finalSum += runningSum;
		depthHelper(node.left, runningSum); 
		depthHelper(node.right, runningSum);
	}

  static class BinaryTree {
    int value;
    BinaryTree left;
    BinaryTree right;

    public BinaryTree(int value) {
      this.value = value;
      left = null;
      right = null;
    }
  }
}

The algorithm itself is fairly simple.

There is a runningSum variable (initialized to -1 to account for the root) to which I add 1, every time I visit a new node (ie: one level down from it's parent). And, the value of this runningSum variable is added to the finalSum variable at each recursive call.

As an example, at node 2, runningSum is 1, and this gets added to finalSum which was 0. Now finalSum becomes 1. Same for node 3, after which finalSum becomes 2. At node 4, runningSum becomes 2 and finalSum becomes 4.

The first test case passes, and I get this message -

计算二叉树中所有节点的深度

But then, all the subsequent cases fail. I think what may be happening is - the output from the previous test case execution is not cleared, and somehow gets added to the result of the current test case execution.

Here's why I think that may be the reason -

 1. Test case 2 - our code output - 0,  your code output - 16
 2. Test case 3 - our code output - 1,  your code output - 17
 3. Test case 4 - our code output - 2,  your code output - 19
 4. Test case 5 - our code output - 4,  your code output - 23
 5. Test case 6 - our code output - 21,  your code output - 44
 6. Test case 7 - our code output - 42,  your code output - 86

Notice how the result from a previous execution isn't cleared and gets added to the "our code output" of the subsequent execution. For instance, in the second test case, the "your code output" result shows 16 which was actually the result of the first test case.

Is this due to the usage of a global static variable in the code? But I've used the same approach several times on Leetcode, and it worked well there.

Or is there a different bug in my algorithm?

PS - I know using screenshots is frowned upon here, but there is a chance this is a platform-specific issue, so I had to use it.

答案1

得分: 5

以下是翻译好的部分:

在我看来,这种行为发生并不是一个错误。这是因为把一切都变成了静态的。有很多方法可以避免这个问题。其中两种在这里解释:

使用静态方法,但是使用无状态类:

public static int nodeDepths(BinaryTree root) {
    // 在这里编写你的代码。
    return depthHelper(root.left, 1) + depthHelper(root.right, 1);
}

private static int depthHelper(BinaryTree node, int sum) {
    if (node == null) return 0;
    return sum + depthHelper(node.left, sum + 1) + depthHelper(node.right, sum + 1);
}

创建一个对象(如果你不只是在对象上执行一个操作,则变得更有用):

public static int nodeDepths(BinaryTree root) {
    // 在这里编写你的代码。
    return new Program().depthSum(root); // 调用非静态方法
    // 这样你可以使用你的原始实现,但是类变量(finalSum)也必须是非静态的
}

这两种实现都是线程安全的。

英文:

In my opition it is not a bug that this behavior occurs. It is due to making everything static. There are many possibilities to avoid this problem. Two of them explained here:

Using static methods but with stateless class:

public static int nodeDepths(BinaryTree root) {
    // Write your code here.
    return depthHelper(root.left, 1) + depthHelper(root.right, 1);
}

private static int depthHelper(BinaryTree node, int sum) {
    if (node == null) return 0;
    return sum + depthHelper(node.left, sum + 1) + depthHelper(node.right, sum + 1);
}

Create an object (becomes more useful if you are not doing just one operation on the object):

public static int nodeDepths(BinaryTree root) {
    // Write your code here.
    return new Program().depthSum(root); // call to non-static method
    // like this you can use your original implementation, but the
    // class variable (finalSum) has to be non-static too
}

Both implementations are thread-safe.

答案2

得分: 1

看起来他们的测试平台会使用一个你的类对象来运行测试。所以你应该在 nodeDepths() 方法的末尾清除 finalSum

public static int nodeDepths(BinaryTree root) {
    // Write your code here.
    int runningSum = 0;
    depthHelper(root.left, runningSum);
    depthHelper(root.right, runningSum);
    int temp = finalSum;  
    finalSum = 0; 
    return temp;
}
英文:

Looks like their testing platform runs tests with one object of your class. So you should clear finalSum at the end of nodeDepths() method:

public static int nodeDepths(BinaryTree root) {
    // Write your code here.
    int runningSum = 0;
    depthHelper(root.left, runningSum);
    depthHelper(root.right, runningSum);
    int temp=finalSum;  
    finalsum=0; 
    return temp;
}

huangapple
  • 本文由 发表于 2020年9月16日 03:30:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/63908662.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定