Problem

Given the root of a binary tree, return its maximum depth.

A binary tree’s maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

Example 1:

Input: root = [3,9,20,null,null,15,7] Output: 3

Example 2: Input: root = [1,null,2] Output: 2

Constraints:

  • The number of nodes in the tree is in the range [0, 104].
  • -100 <= Node.val <= 100

Solution

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/

Modified Level Order Traversal - O(n) time - O(n) space

using namespace std;
 
class Solution {
public:
    int levels;
    void helper(TreeNode* node, int level) {
        if (levels == level) levels++;
        if (node->left != nullptr) helper(node->left, level +1);
        if (node->right != nullptr) helper(node->right, level +1);
    }
	int maxDepth(TreeNode* root) {
		if (root == nullptr) return 0;
        helper(root, 0);
		return levels;
	}
};

Improved Level Order Traversal - O(n) time - O(n) space

class Solution {
  public:
    int maxDepth(TreeNode *root) {
      if (root == nullptr) return 0;
      return max(1 + maxDepth(root -> left), 1 + maxDepth(root -> right));
    }
};

Tail Recursion

class Solution {
  private:
    // The queue that contains the next nodes to visit, 
    //   along with the level/depth that each node is located.
    queue<pair<TreeNode*, int>> next_items;
    int max_depth = 0;
    /**
     * A tail recursion function to calculate the max depth
     *   of the binary tree.
     */
    int next_maxDepth() {
      if (next_items.size() == 0) {
        return max_depth;
      }
 
      auto next_item = next_items.front();
      next_items.pop();
      auto next_node = next_item.first;
      auto next_level = next_item.second + 1;
      max_depth = max(max_depth, next_level);
 
      // Add the nodes to visit in the following recursive calls.
      if (next_node->left != NULL) {
        next_items.push(make_pair(next_node->left, next_level));
      }
      if (next_node->right != NULL) {
        next_items.push(make_pair(next_node->right, next_level));
      }    
      // The last action should be the ONLY recursive call
      //   in the tail-recursion function.
      return next_maxDepth();
    }
    
  public:
    int maxDepth(TreeNode* root) {
      if (root == NULL) return 0; 
      // Clear the previous queue.
      std::queue<pair<TreeNode*, int>> empty;
      std::swap(next_items, empty);
      max_depth = 0;
      // Push the root node into the queue to kick off the next visit.
      next_items.push(make_pair(root, 0));
      return next_maxDepth();
    }
};

Stack

We start from a stack that contains the root node and the corresponding depth which is 1. Then we proceed to the iterations: pop the current node out of the stack and push the child nodes. The depth is updated at each step.

class Solution {
  public:
  int maxDepth(TreeNode* root) {
    if (root == NULL) return 0;
    vector<pair<int, TreeNode*>> my_stack;
    my_stack.push_back(pair<int, TreeNode*>(1, root));
    int max_depth = 0;
 
    while (!my_stack.empty()) {
      pair<int, TreeNode*> my_pair = my_stack.back();
      int c_depth = get<0>(my_pair);
      TreeNode* c_node = get<1>(my_pair);
      max_depth = max(max_depth, c_depth);
      my_stack.pop_back();
      if (c_node->left != NULL) {
        my_stack.push_back(pair<int, TreeNode*>(c_depth + 1, c_node->left));
      }
      if (c_node->right != NULL) {
        my_stack.push_back(pair<int, TreeNode*>(c_depth + 1, c_node->right));
      }
    }
    return max_depth;
  }
};