[Code random thoughts] Binary tree brushing questions

theoretical basis

Full binary tree : A binary tree has only nodes with degree 0 and nodes with degree 2, and the nodes with degree 0 are on the same level

Complete binary tree : number the nodes from top to bottom, left to right, and all the numbers can correspond to the numbers in the full binary tree of the same height

Binary search tree : the elements it stores must comparable

  • The value of any node is greater than the value of all nodes in its left subtree
  • The value of any node is less than the value of all nodes in its right subtree
  • Its left and right subtrees are also a binary search tree

Balanced binary search tree (AVL tree): It is an empty tree, or the absolute value of the height difference between its left and right subtrees does not exceed 1 , and both left and right subtrees are a balanced binary tree

Binary tree storage method

Chain storage:

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;
    }
}

Sequential storage:

a
------
|    |
b    c
--------
| |  | |
d e  f g

下标 i 从 0 开始
- 左子树: 2i + 1
- 右子树: 2i + 2
-------------------
0  1  2  3  4  5  6
a, b, c, d, e, f, g
-------------------

下标 i 从 1 开始
- 左子树: 2i
- 右子树: 2i + 1
----------------------
0  1  2  3  4  5  6  7
-  a, b, c, d, e, f, g
----------------------

Binary tree traversal

front-middle-back order traversal

The nature of recursion:

  • Each recursive call will push the function's local variables , parameter values ​​and return address into the call stack
  • When recursively returns, the parameters of the last recursion are popped from the top of the stack
  • This is why recursion can return to the previous position

Preorder traversal : 144. Preorder traversal of binary trees

// 递归实现
class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new ArrayList<>(); 
        dfs(root, list);
        return list;
    }

    void dfs(TreeNode node, List<Integer> list) {
    
    
        if (node == null) return;
        list.add(node.val); // 根
        dfs(node.left, list); // 左
        dfs(node.right, list); // 右
    }
}
// 迭代实现
class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if (root != null) stack.push(root);
        while (!stack.isEmpty()) {
    
    
            TreeNode node = stack.pop();
            res.add(node.val);
            if (node.right != null) stack.push(node.right); // 右
            if (node.left != null) stack.push(node.left); // 左
        }
        return res;
    }
}

Post-order traversal : 145. Post-order traversal of binary trees

// 递归实现
class Solution {
    
    
    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new ArrayList<>();
        dfs(root, list);
        return list;
    }

    void dfs(TreeNode node, List<Integer> list) {
    
    
        if (node == null) return;
        dfs(node.left, list); // 左
        dfs(node.right, list); // 右
        list.add(node.val); // 根
    }
}
// 迭代实现
public List<Integer> postorderTraversal(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	if (root == null) return res;

	Stack<TreeNode> stack = new Stack<>();
	stack.add(root);

	while (!stack.isEmpty()) {
    
    
		TreeNode node = stack.pop();
		res.add(node.val);
		if (node.left != null) stack.add(node.left); // 左
		if (node.right != null) stack.add(node.right); // 右
	}

	Collections.reverse(res); // 反转
	return res;
}

Inorder traversal : 94. Inorder traversal of a binary tree

// 递归实现
class Solution {
    
    
    List<Integer> res = new ArrayList<>();

    public List<Integer> inorderTraversal(TreeNode root) {
    
    
        dfs(root);
        return res;
    }

    void dfs(TreeNode node) {
    
    
        if (node == null) return;
        dfs(node.left); // 左
        res.add(node.val); // 根
        dfs(node.right); // 右
    }
}

The iterative implementation of in-order traversal is not easy to remember. It is recommended to remember the following iterative writing method

// 迭代实现1
public List<Integer> inorderTraversal(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	Stack<TreeNode> st = new Stack<>();
	TreeNode cur = root;
	while (cur != null || !st.isEmpty()) {
    
    
		if (cur != null) {
    
     // *
			st.push(cur);
			cur = cur.left;
		} else {
    
     // *
			cur = st.pop();
			res.add(cur.val);
			cur = cur.right;
		}
	}
	return res;
}

// 迭代实现2
public List<Integer> inorderTraversal(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	Stack<TreeNode> st = new Stack<>();
	TreeNode cur = root;
	while (cur != null || !st.isEmpty()) {
    
    
		while (cur != null) {
    
     // *
			st.push(cur);
			cur = cur.left;
		} 
		cur = st.pop();
		res.add(cur.val);
		cur = cur.right;
	}
	return res;
}

Unified iterative writing*

In this way, the three traversals can be realized only by adjusting the code order:

// 中序遍历
public List<Integer> inorderTraversal(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	if (root == null) return res;
	Stack<Object> st = new Stack<>();
	st.push(root);
	while (!st.empty()) {
    
    
		Object o = st.pop();
		if (o instanceof TreeNode) {
    
    
			TreeNode node = (TreeNode) o;
			if (node.right != null) st.push(node.right); // *
			st.push(node.val); // *
			if (node.left != null) st.push(node.left); // *
		} else {
    
    
			res.add((Integer) o);
		}
	}
	return res;
}

// 先序遍历
public List<Integer> preorderTraversal(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	if (root == null) return res;
	Stack<Object> st = new Stack<>();
	st.push(root);
	while (!st.empty()) {
    
    
		Object o = st.pop();
		if (o instanceof TreeNode) {
    
    
			TreeNode node = (TreeNode) o; // *
			if (node.right != null) st.push(node.right); // *
			if (node.left != null) st.push(node.left); // *
			st.push(node.val);
		} else {
    
    
			res.add((Integer) o);
		}
	}
	return res;
}

// 后序遍历
public List<Integer> postorderTraversal(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	if (root == null) return res;
	TreeNode cur = root;
	Stack<Object> st = new Stack<>();
	st.push(cur);
	while (!st.isEmpty()) {
    
    
		Object o = st.pop();
		if (o instanceof TreeNode) {
    
    
			TreeNode node = (TreeNode) o;
			st.push(node.val); // *
			if (node.right != null) st.push(node.right); // *
			if (node.left != null) st.push(node.left); // *
		} else {
    
    
			res.add((Integer)o);
		}
	}
	return res;
}

sequence traversal

Topic: 102. Level Order Traversal of Binary Tree - LeetCode

public List<List<Integer>> levelOrder(TreeNode root) {
    
    
	List<List<Integer>> res = new ArrayList<>();
	if (root == null) return res;
	Queue<TreeNode> q = new LinkedList<>();
	q.add(root);
	while (!q.isEmpty()) {
    
    
		List<Integer> tmpList = new ArrayList<>();
		for (int i = q.size(); i > 0; i--) {
    
    
			TreeNode node = q.poll();
			tmpList.add(node.val);
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
		res.add(tmpList);
	}
	return res;
}

Sequential traversal related topics

Level Order Traversal of Binary Tree II

Topic: 107. Level Order Traversal of Binary Tree II - LeetCode

Given the root node of your binary tree root, return its node value Bottom -up order traversal . (That is, traverse from left to right layer by layer from the layer where the leaf node is located to the layer where the root node is located)

public List<List<Integer>> levelOrderBottom(TreeNode root) {
    
    
	List<List<Integer>> res = new ArrayList<>();
	if (root == null) return res;
	Deque<TreeNode> q = new ArrayDeque<>();
	q.add(root);
	while (!q.isEmpty()) {
    
    
		List<Integer> tmpList = new ArrayList<>();
		for (int i = q.size(); i > 0; i--) {
    
    
			TreeNode node = q.poll();
			tmpList.add(node.val);
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
		res.add(0, tmpList); // 往头部放
	}
	return res;
}

Right View of Binary Tree

Title: 199. Right View of Binary Tree - LeetCode

Given the root node root , imagine yourself standing on the right side of it, and return the values ​​of the nodes you can see from the right side in order from top to bottom.

Add the last value of the hierarchy traversal to the result each time:

public List<Integer> rightSideView(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	if (root == null) return res;
	Queue<TreeNode> q = new LinkedList<>();
	q.add(root);
	while (!q.isEmpty()) {
    
    
		for (int i = q.size(); i > 0; i--) {
    
    
			TreeNode node = q.poll();
			if (i == 1) res.add(node.val);
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
	}
	return res;
}

dfs adds to the result the right element at that depth the first time it is visited:

class Solution {
    
    
    List<Integer> res = new ArrayList<>();

    public List<Integer> rightSideView(TreeNode root) {
    
    
        dfs(root, 0);
        return res;
    }

    void dfs(TreeNode node, int depth) {
    
    
        if (node == null) return;
        // 第一次访问这个深度
        if (depth == res.size()) res.add(node.val);
        dfs(node.right, depth + 1);
        dfs(node.left, depth + 1);
    }
}

Layer average of binary tree

Topic: 637. Layer Average of Binary Tree - LeetCode

Given the root node of a non-empty binary tree root, return the average value of each level of nodes in the form of an array. Answers that are 10^-5within are accepted.

public List<Double> averageOfLevels(TreeNode root) {
    
    
	List<Double> res = new ArrayList<>();
	if (root == null) return res;
	Queue<TreeNode> q = new LinkedList<>();
	q.add(root);
	while (!q.isEmpty()) {
    
    
		double sum = 0;
		int n = q.size();
		for (int i = n; i > 0; i--) {
    
    
			TreeNode node = q.poll();
			sum += node.val;
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
		res.add(sum / n);
	}
	return res;
}

Level order traversal of N-ary tree

Topic: 429. Level order traversal of N-ary tree - LeetCode

public List<List<Integer>> levelOrder(Node root) {
    
    
	List<List<Integer>> res = new ArrayList<>();
	if (root == null) return res;
	Queue<Node> q = new LinkedList<>();
	q.add(root);
	while (!q.isEmpty()) {
    
    
		List<Integer> tmpList = new ArrayList<>();
		for (int i = q.size(); i > 0; i--) {
    
    
			Node node = q.poll();
			tmpList.add(node.val);
			for (Node n : node.children) q.add(n);
		}
		res.add(tmpList);
	}
	return res;
}

Find the maximum value in each tree row

Topic: 515. Finding the Maximum in Each Tree Row - LeetCode

Given the root node of a binary tree root, find the maximum value at each level of the binary tree.

public List<Integer> largestValues(TreeNode root) {
    
    
	List<Integer> res = new ArrayList<>();
	if (root == null) return res;
	Queue<TreeNode> q = new LinkedList<>();
	q.add(root);
	while (!q.isEmpty()) {
    
    
		int max = Integer.MIN_VALUE;
		for (int i = q.size(); i > 0; i--) {
    
    
			TreeNode node = q.poll();
			max = Math.max(max, node.val);
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
		res.add(max);
	}
	return res;
}

Fill the next right node pointer for each node

Topic: 116. Fill the next right node pointer of each node - LeetCode

Layer order traversal:

public Node connect(Node root) {
    
    
	if (root == null) return root;
	Queue<Node> q = new LinkedList<>();
	q.add(root);
	while (!q.isEmpty()) {
    
    
		for (int i = q.size(); i > 0; i--) {
    
    
			Node node = q.poll();
			if (i > 1) node.next = q.peek(); // 除最后一个元素,都指向下一元素
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
	}
	return root;
}

DFS:

public Node connect(Node root) {
    
    
	if (root == null) return root;
	if (root.left != null) {
    
    
		root.left.next = root.right; // 亲兄弟建立连接
		if (root.next != null) // 堂兄弟建立连接
			root.right.next = root.next.left;
	}
	connect(root.left);
	connect(root.right);
	return root;
}

Fill each node's next right node pointer II

Topic: 117. Fill the next right node pointer of each node II - LeetCode

If this problem is solved by layer order traversal, it is exactly the same as 116. Filling the next right node pointer of each node - LeetCode .

DFS approach:

class Solution {
    
    
    public Node connect(Node root) {
    
    
        if (root == null) return root;
        // 左右子树都不为 null, 直接连接
        if (root.left != null && root.right != null)
            root.left.next = root.right;
        // 左不为 null, 右为 null, 则右子树的 next 由根的 next 得出
        if (root.left != null && root.right == null)
            root.left.next = getNext(root.next);
        // 右不为 null
        if (root.right != null)
            root.right.next = getNext(root.next);
        connect(root.right); // 必须先 right 再 left
        connect(root.left);
        return root;
    }
    // 找到 node 最左的第一个节点
    Node getNext(Node node) {
    
    
        if (node == null) return null;
        // 先尝试找左节点
        if (node.left != null) return node.left;
        // 再尝试找右节点
        if (node.right != null) return node.right;
        // 左右节点都不存在,尝试对 node.next 进行相同操作
        if (node.next != null) return getNext(node.next);
        return null;
    }
}

The maximum depth of the binary tree

Topic: 104. Maximum depth of a binary tree - LeetCode

Given a binary tree, find its maximum depth.
The depth of a binary tree is the number of nodes on the longest path from the root node to the furthest leaf node.

recursion:

public int maxDepth(TreeNode root) {
    
    
	if (root == null) return 0;
	return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}

DFS:

class Solution {
    
    
    int maxLevel = 0;

    public int maxDepth(TreeNode root) {
    
    
        dfs(root, 1);
        return maxLevel;
    }

    void dfs(TreeNode node, int level) {
    
    
        if (node == null) return;
        if (level > maxLevel) maxLevel = level;
        dfs(node.left, level + 1);
        dfs(node.right, level + 1);
    }
}

BFS:

public int maxDepth(TreeNode root) {
    
    
	if (root == null) return 0;
	Deque<TreeNode> q = new ArrayDeque<>();
	q.add(root);
	int cnt = 0;
	while (!q.isEmpty()) {
    
    
		for (int i = q.size(); i > 0; i--) {
    
    
			TreeNode node = q.poll();
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
		cnt ++ ;
	}
	return cnt;
}

The minimum depth of a binary tree

Topic: 111. Minimum depth of a binary tree - LeetCode

Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes on the shortest path from the root node to the nearest leaf node.

Level order traversal: fastest

public int minDepth(TreeNode root) {
    
    
	if (root == null) return 0;
	Queue<TreeNode> q = new LinkedList<>();
	q.add(root);
	int level = 1;
	while (!q.isEmpty()) {
    
    
		for (int i = q.size(); i > 0; i--) {
    
    
			TreeNode node = q.poll();
			// 层序遍历时, 遇到第一个叶子节点,返回当前树的高度
			if (node.left == null && node.right == null)
				return level;
			if (node.left != null) q.add(node.left);
			if (node.right != null) q.add(node.right);
		}
		level++;
	}
	return level;
}

DFS:

class Solution {
    
    
    int minLevel = Integer.MAX_VALUE;

    public int minDepth(TreeNode root) {
    
    
        if (root == null) return 0;
        dfs(root, 1);
        return minLevel;
    }

    void dfs(TreeNode node, int level) {
    
    
        if (node == null) return;
        if (node.left == null && node.right == null)
            minLevel = Math.min(minLevel, level);
        dfs(node.left, level + 1);
        dfs(node.right, level + 1);
    }
}

recursion:

public int minDepth(TreeNode root) {
    
    
	if (root == null) return 0;
	// 处理只有一个子节点的情况
	if (root.left == null && root.right != null)
		return minDepth(root.right) + 1;
	if (root.right == null && root.left != null)
		return minDepth(root.left) + 1;
	return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
}

Binary tree topic

Flip a binary tree

Title: 226. Flip Binary Tree - LeetCode

Given the root of a binary tree root, flip the tree and return its root.

recursion:

public TreeNode invertTree(TreeNode root) {
    
    
	if (root == null) return null;

	// 交换左右子节点
	TreeNode tmpNode = root.left;
	root.left = root.right;
	root.right = tmpNode;

	invertTree(root.left);
	invertTree(root.right);
	return root;
}

BFS:

public TreeNode invertTree(TreeNode root) {
    
    
	if (root == null) return null;
	Queue<TreeNode> queue = new LinkedList<>();
	queue.offer(root);
	while (!queue.isEmpty()) {
    
    
		TreeNode node = queue.poll();
		// 交换子树
		TreeNode t = node.right;
		node.right = node.left;
		node.left = t;
		if (node.left != null) queue.offer(node.left);
		if (node.right != null) queue.offer(node.right);
	}
	return root;
}

DFS:

public TreeNode invertTree(TreeNode root) {
    
    
	if (root == null) return null;
	// 交换子树
	TreeNode t = invertTree(root.left);
	root.left = invertTree(root.right);
	root.right = t;
	return root;
}

Symmetric Binary Tree

Topic: 101. Symmetric Binary Tree - LeetCode

Given the root of a binary tree root, check if it is axisymmetric.

recursion:

class Solution {
    
    
    public boolean isSymmetric(TreeNode root) {
    
    
        if (root == null) return true;
        return helper(root.left, root.right);
    }

    boolean helper(TreeNode n1, TreeNode n2) {
    
    
        if (n1 == null && n2 == null) return true;
        if (n1 == null || n2 == null || n1.val != n2.val) return false;
        return helper(n1.left, n2.right) && helper(n1.right, n2.left); 
    }
}

Iteration: level order traversal

public boolean isSymmetric(TreeNode root) {
    
    
	Queue<TreeNode> q = new LinkedList<>();
	q.offer(root.left);
	q.offer(root.right);
	while (!q.isEmpty()) {
    
    
		TreeNode n1 = q.poll();
		TreeNode n2 = q.poll();
		if (n1 == null && n2 == null) continue;
		if (n1 == null || n2 == null || n1.val != n2.val)
			return false;
		q.offer(n1.left);
		q.offer(n2.right);
		q.offer(n1.right);
		q.offer(n2.left);
	}
	return true;
}

The number of nodes in a complete binary tree*

Topic: 222. The number of nodes in a complete binary tree - LeetCode

Given the root node of a complete binary tree root, find the number of nodes in the tree.

Using the properties of a complete binary tree:

class Solution {
    
    
    public int countNodes(TreeNode root) {
    
    
        if (root == null) return 0;
        int l = getHeight(root.left); // 左子树的高度
        int r = getHeight(root.right); // 右子树的高度
        if (l == r) {
    
    
            // 左右子树高度相等,表示左子树一定是满二叉树
            // 用公式计算左子树的节点个数:2^l - 1
            // 递归计算右子树的节点个数 countNodes(root.right)
            // 再 + 1 (当前节点)
            return countNodes(root.right) + (1 << l); // 1 << l == 2^l
        } else {
    
    
            // 最后一层不满,但是倒数第二层是满的,右子树一定是满二叉树
            // 公式计算右子树的节点个数: 2^r - 1
            // 递归计算左子树的节点个数 countNodes(root.left)
            // 再 + 1 (当前节点)
            return countNodes(root.left) + (1 << r); // 1 << r == 2^r
        }
    }

    // 完全二叉树计算高度
    int getHeight(TreeNode node) {
    
    
        int height = 0;
        while (node != null) {
    
    
            node = node.left;
            height++;
        }
        return height;
    }
}

recursion:

public int countNodes(TreeNode root) {
    
    
	if (root == null) return 0;
	return countNodes(root.left) + countNodes(root.right) + 1;
}

DFS:

class Solution {
    
    
    int num = 0;

    public int countNodes(TreeNode root) {
    
    
        dfs(root);
        return num;
    }

    void dfs(TreeNode node) {
    
    
        if (node == null) return;
        num++;
        dfs(node.left);
        dfs(node.right);
    }
}

Layer order traversal:

public int countNodes(TreeNode root) {
    
    
	if (root == null) return 0;
	Queue<TreeNode> q = new LinkedList<>();
	q.offer(root);
	int count = 0;
	while (!q.isEmpty()) {
    
    
		TreeNode node = q.poll();
		if (node.left != null) q.offer(node.left);
		if (node.right != null) q.offer(node.right);
		count++;
	}
	return count;
}

Balanced Binary Tree*

Topic: 110. Balanced Binary Tree - LeetCode

Given a binary tree, determine whether it is a height-balanced binary tree.

In this question, a height-balanced binary tree is defined as: the absolute value of the height difference between the left and right subtrees of each node of a binary tree does not exceed 1.

recursion:

class Solution {
    
    
    public boolean isBalanced(TreeNode root) {
    
    
        if (root == null) return true;
        if (Math.abs(getHeight(root.left) - getHeight(root.right)) > 1) return false;
        return isBalanced(root.left) && isBalanced(root.right); 
    }
    int getHeight(TreeNode node) {
    
    
        if (node == null) return 0;
        int leftH = getHeight(node.left);
        int rightH = getHeight(node.right);
        return Math.max(leftH, rightH) + 1;
    }
}

Recursion with pruning:

class Solution {
    
    
    public boolean isBalanced(TreeNode root) {
    
    
        return getHeight(root) != -1;
    }

    int getHeight(TreeNode node) {
    
    
        if (node == null) return 0;
        int leftH = getHeight(node.left); // 左子树高度
        int rightH = getHeight(node.right); // 右子树高度
        // 剪枝:左子树 或 右子树 不满足条件 或 当前节点不满足条件,直接返回 -1
        if (leftH == -1 || rightH == -1 || Math.abs(leftH - rightH) > 1) return -1;
        // 左右子树都满足条件,返回当前节点的高度
        return Math.max(leftH, rightH) + 1;
    }
}

All paths in the binary tree

Title: 257. All paths in a binary tree - LeetCode

Given the root of a binary tree ,root return all paths from the root to the leaves, in any order.

DFS + StringBuilder:

class Solution {
    
    
    List<String> res = new ArrayList<>();
    
    public List<String> binaryTreePaths(TreeNode root) {
    
    
        dfs(new StringBuilder(), root); 
        return res;
    }

    void dfs(StringBuilder path, TreeNode node) {
    
    
        if (node == null) return;
        path.append(node.val); 
        if (node.left == null && node.right == null) {
    
    
            res.add(path.toString());
            return;
        }
        dfs(new StringBuilder(path).append("->"), node.left);
        dfs(new StringBuilder(path).append("->"), node.right);
    }
}

subtree of another tree

Title: 572. Subtree of Another Tree - LeetCode

You are given two binary trees rootand subRoot. rootTests that contains subRoota subtree with the same structure and node values ​​as . If it exists, return it true; otherwise, return it false.
A subtree treeof a binary tree includes treea node of and all descendant nodes of this node. treeIt can also be seen as a subtree of itself.

class Solution {
    
    
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
    
    
        if (root == null) return false; 
        if (isSameTree(root, subRoot)) return true;
        return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
    }
    // 判断 n1 和 n2 是否是相同的树
    boolean isSameTree(TreeNode n1, TreeNode n2) {
    
    
        if (n1 == null && n2 == null) return true;
        if (n1 == null || n2 == null || n1.val != n2.val) return false;
        return isSameTree(n1.left, n2.left) && isSameTree(n1.right, n2.right);
    }
}

sum of left leaves

Title: 404. The sum of the left leaves - LeetCode

Given the root node of a binary tree root, return the sum of all left leaves.

DFS:

class Solution {
    
    
    int res = 0;
    public int sumOfLeftLeaves(TreeNode root) {
    
    
        if (root.left == null && root.right == null) return 0;
        dfs(root, null);
        return res;
    }
    // DFS 时传入 parent 节点用来判断是否是左叶子
    void dfs(TreeNode node, TreeNode parent) {
    
    
        if (node == null) return;
        // 判断是左叶子
        if (node.left == null && node.right == null && parent.left == node)
            res += node.val;
        dfs(node.left, node);
        dfs(node.right, node);
    }
}

recursion:

public int sumOfLeftLeaves(TreeNode root) {
    
    
	if (root == null) return 0;
	int res = 0;
	if (root.left != null && root.left.left == null && root.left.right == null)
		res += root.left.val;
	return  sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right) + res;
}

Find the value in the lower left corner of the tree

Topic: 513. Find the value in the lower left corner of the tree - LeetCode

Given the root node root , find the value of the bottommost leftmost node of the binary tree.

Layer order traversal: each layer updates res to the value of the first node in the current layer

public int findBottomLeftValue(TreeNode root) {
    
    
	Queue<TreeNode> q = new LinkedList<>();
	q.offer(root);
	int res = root.val;
	while (!q.isEmpty()) {
    
    
		int size = q.size();
		for (int i = size; i > 0; i--) {
    
    
			TreeNode node = q.poll();
			if (node.left != null) q.offer(node.left);
			if (node.right != null) q.offer(node.right);
			if (i == size) res = node.val; // 每次更新为当前层第一个节点的值
		}
	} 
	return res;
}

DFS: traverse and find the depth of the tree at the same time

// DFS:遍历同时求出树的深度
class Solution {
    
    
    int maxLevel = Integer.MIN_VALUE;
    int res;

    public int findBottomLeftValue(TreeNode root) {
    
    
        dfs(root, 0);     
        return res;
    }
    
    void dfs(TreeNode node, int level) {
    
    
        if (node == null) return;
        if (node.left == null && node.right == null)
            if (level > maxLevel) {
    
    
                maxLevel = level;
                res = node.val;
            }
        dfs(node.left, level + 1);
        dfs(node.right, level + 1); 
    }
}

path sum

Title: 112. Path Sum - LeetCode

You are given the root node of the binary tree rootand an integer representing the target sum targetSum. Determine whether there is a path from the root node , and the sum of all node values ​​on this path is equal to the target sum targetSum. If it exists, return it true; otherwise, return it false.

DFS template:

class Solution {
    
    
    public boolean hasPathSum(TreeNode root, int targetSum) {
    
    
        return dfs(root, 0, targetSum);
    }

    boolean dfs(TreeNode node, int sum, int targetSum) {
    
    
        if (node == null) return false;
        if (node.left == null && node.right == null && sum + node.val == targetSum)
            return true;
        return dfs(node.left, node.val + sum, targetSum)
                || dfs(node.right, node.val + sum, targetSum);
    }
}

Use -the operator to optimize away extra parameters:

public boolean hasPathSum(TreeNode root, int targetSum) {
    
    
	if (root == null) return false;
	if (root.left == null && root.right == null && root.val == targetSum)
		return true;
	return hasPathSum(root.left, targetSum - root.val)
			|| hasPathSum(root.right, targetSum - root.val);
}

Constructs a binary tree from inorder and postorder traversal sequences*

Topic: 106. Construct Binary Tree from Inorder and Postorder Traversal Sequences - LeetCode

Given two integer arrays inorderand postorder, where inorderis the inorder traversal of a binary tree and postorderthe postorder traversal of the same tree, please construct and return this binary tree .

Reference question solution: Graphical construction of binary tree inorder + postorder

recursion:

public TreeNode buildTree(int[] inorder, int[] postorder) {
    
    
	if (inorder.length == 0) return null;
	if (inorder.length == 1) return new TreeNode(inorder[0]);
	// 初始化根节点
	TreeNode root = new TreeNode(postorder[postorder.length - 1]);
	// 在 inorder[] 中找到根的位置
	for (int i = 0; i < inorder.length; i++) {
    
    
		if (inorder[i] == root.val) {
    
    
			root.left = buildTree(
				Arrays.copyOfRange(inorder, 0, i),
				Arrays.copyOfRange(postorder, 0, i));
			root.right = buildTree(
				Arrays.copyOfRange(inorder, i + 1, inorder.length),
				Arrays.copyOfRange(postorder, i, postorder.length - 1));
			break;
		}
	}
	return root;
}

Recursive optimization: pass in index for optimization + array simulation hash

class Solution {
    
    
    int[] inorder_map = new int[6001]; // 数组模拟哈希
    public TreeNode buildTree(int[] inorder, int[] postorder) {
    
    
        if (inorder.length == 1) return new TreeNode(inorder[0]);
        // 下标映射
        for (int i = 0; i < inorder.length; i++) 
            inorder_map[inorder[i] + 3000] = i; // 映射防越界
        return help(inorder, 0, inorder.length - 1, 
                      postorder, 0, postorder.length - 1);
    }

    // inorder [s1, e1] postorder [s2, e2]
    TreeNode help(int[] inorder, int s1, int e1, int[] postorder, int s2, int e2) {
    
    
        if (s1 > e1 || s2 > e2) return null;
        int rootVal = postorder[e2]; // 根节点的值
        TreeNode root = new TreeNode(rootVal); // 初始化根节点
        int rootValIdx = inorder_map[rootVal + 3000]; // 中序遍历中根节点值的下标
        // 左子树长度 = rootValIx - s1 -1
        // s2 + rootValIdx - s1 - 1 表示计算 后序数组 的结束位置,
        root.left = help(inorder, s1, rootValIdx - 1,
                         postorder, s2, s2 + rootValIdx - s1 - 1);
        root.right = help(inorder, rootValIdx + 1, e1,
                          postorder, s2 + rootValIdx - s1, e2 - 1);
        return root;
    }
}

Construct a binary tree from preorder and inorder traversal sequences

Topic: 105. Construct Binary Tree from Preorder and Inorder Traversal Sequences - LeetCode

Given two integer arrays preorderand inorder, where preorderis the preorder traversal of a binary tree and is the inorder traversalinorder of the same tree , construct a binary tree and return its root node.

public TreeNode buildTree(int[] preorder, int[] inorder) {
    
    
	// preorder = [3,9,20,15,7] -> [3] [9] [20, 15, 7] 根左右
	// inorder = [9,3,15,20,7] -> [9] [3] [15, 20, 7] 左根右
	if (preorder.length == 0) return null;
	TreeNode root = new TreeNode(preorder[0]);
	for (int i = 0; i < inorder.length; i++) {
    
    
		if (inorder[i] == root.val) {
    
    
			root.left = buildTree(
				Arrays.copyOfRange(preorder, 1, i + 1),
				Arrays.copyOfRange(inorder, 0, i)
			);
			root.right = buildTree(
				Arrays.copyOfRange(preorder, i + 1, preorder.length),
				Arrays.copyOfRange(inorder, i + 1, inorder.length)
			);
			break;
		}
	}
	return root;
}

maximum binary tree

Title: 654. Maximum Binary Tree - LeetCode

Given a non-repeating array of integers nums. The largest binary tree can be constructed numsrecursively :

  1. Creates a root node whose value is the maximum value numsin .
  2. Recursively builds the left subtree on the subarray prefix to the left of the maximum value.
  3. Recursively builds the right subtree on the subarray suffix to the right of the maximum value.

numsReturns the largest binary tree constructed by .

recursion:

public TreeNode constructMaximumBinaryTree(int[] nums) {
    
    
	if (nums.length == 0) return null;
	int maxIdx = 0;
	for (int i = 0; i < nums.length; i++) 
		if (nums[i] > nums[maxIdx]) maxIdx = i;
	TreeNode root = new TreeNode(nums[maxIdx]);
	root.left = constructMaximumBinaryTree(Arrays.copyOfRange(nums, 0, maxIdx));
	root.right = constructMaximumBinaryTree(Arrays.copyOfRange(nums, maxIdx + 1, nums.length));
	return root;
}

Optimize array slicing operations with indexing:

class Solution {
    
    
    public TreeNode constructMaximumBinaryTree(int[] nums) {
    
    
        return help(nums, 0, nums.length - 1);
    }
    
    TreeNode help(int[] nums, int l, int r) {
    
    
        if (l > r) return null;
        int maxIdx = l;
        for (int i = l; i <= r; i++)
            if (nums[i] > nums[maxIdx]) maxIdx = i;
        TreeNode root = new TreeNode(nums[maxIdx]);
        root.left = help(nums, l, maxIdx - 1);
        root.right = help(nums, maxIdx + 1, r);
        return root;
    }
}

merge binary tree

Topic: 617. Merge Binary Trees - LeetCode

You are given two binary trees: root1and root2.
Imagine that when you overlay one tree on top of the other, some nodes on both trees will overlap (and others won't). You need to merge these two trees into a new binary tree. The rule of merging is: if two nodes overlap, then add the values ​​of these two nodes as the new value of the merged node; otherwise, the node that is not null will be directly used as the node of the new binary tree.
Note : The merging process must start from the root node of both trees.

public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
    
    
	if (root1 == null) return root2;
	if (root2 == null) return root1;
	TreeNode root = new TreeNode(root1.val + root2.val);
	root.left = mergeTrees(root1.left, root2.left);
	root.right = mergeTrees(root1.right, root2.right);
	return root;
}

Binary search tree topic

Validate a binary search tree

Topic: 98. Verifying a Binary Search Tree - LeetCode

Given the root node of a binary tree root, determine whether it is a valid binary search tree.
A valid binary search tree is defined as follows:

  • A node's left subtree contains only numbers less than the current node.
  • The right subtree of a node contains only numbers greater than the current node.
  • All left and right subtrees must themselves be binary search trees.

Inorder DFS:

class Solution {
    
    
    long preVal = Long.MIN_VALUE;

    public boolean isValidBST(TreeNode root) {
    
    
        if (root == null) return true;
        // 左
        if (!isValidBST(root.left)) return false;
        // 中
        if (root.val <= preVal) return false; 
        preVal = root.val; // 保存上一次遍历时的值
        // 右
        return isValidBST(root.right);
    }
}

Minimum absolute difference of binary search tree

Title: 530. Minimum Absolute Difference of Binary Search Tree - LeetCode

Given the root node of a binary search tree root, return the minimum difference between the values ​​of any two distinct nodes in the tree .
Difference is a positive number whose value is equal to the absolute value of the difference between the two values.

Inorder DFS:

class Solution {
    
    
    int res = Integer.MAX_VALUE;
    int prev = -100010; // 记录上一个节点的值
    
    public int getMinimumDifference(TreeNode root) {
    
    
        dfs(root);
        return res;
    }

    void dfs(TreeNode node) {
    
    
        if (node == null) return;
		// 左
        dfs(node.left);
		// 中
        res = Math.min(res, node.val - prev);
        prev = node.val; // 记录上一个节点的值
		// 右
        dfs(node.right);
    }
}

Modes in Binary Search Trees

Topic: 501. Moderate Numbers in Binary Search Tree - LeetCode

Given the root of a binary search tree (BST) with duplicate values , find and return all modes (ie, elements that occur most frequently) inroot the BST . If there is more than one mode in the tree, it can be returned in any order. Assume that BST satisfies the following definition:

  • The value of the node contained in the left subtree of the node is less than or equal to the value of the current node
  • The value of the node contained in the right subtree of the node is greater than or equal to the value of the current node
  • Both left and right subtrees are binary search trees

Processing of general binary trees:

class Solution {
    
    
    final int N = 100010;
    int[] map = new int[N + N]; // 某个数字的出现次数
    int maxCount = 0; // 某个数字出现最多的次数
    public int[] findMode(TreeNode root) {
    
    
        dfs(root);
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < map.length; i++)
            if (map[i] == maxCount)  list.add(i - N);
        int[] res = new int[list.size()];
        int k = 0;
        for (Integer i : list) res[k++] = i;
        return res;
    }
    void dfs(TreeNode root) {
    
    
        if (root == null) return;
        dfs(root.left);
        map[root.val + N]++; // 映射为正值
        maxCount = Math.max(maxCount, map[root.val + N]);
        dfs(root.right);
    }
}

Optimize for a binary search tree:

class Solution {
    
    
    List<Integer> list = new ArrayList<>();
    int preVal = 0; // 上一个值
    int curTimes = 0; // 当前值的出现次数
    int  maxTimes = 0; // 最大的出现次数

    public int[] findMode(TreeNode root) {
    
    
        dfs(root);
        int[] res = new int[list.size()];
        int k = 0;
        for (Integer i : list) res[k++] = i;
        return res;
    }

    void dfs(TreeNode node) {
    
    
        if (node == null) return;
        dfs(node.left);
        // 判断 当前值 与 上一个值 的关系
        if (preVal == node.val) curTimes++;
        else {
    
    
            preVal = node.val;
            curTimes = 1;
        }
        // 判断 当前数量 和 最大数量 的关系
        if (curTimes == maxTimes) list.add(node.val);
        else if (curTimes > maxTimes) {
    
    
            list.clear();
            list.add(node.val);
            maxTimes = curTimes;
        }
        dfs(node.right);
    }
}

The nearest common ancestor of the binary tree**

Topic: 236. The nearest common ancestor of a binary tree - LeetCode

Given a binary tree, find the nearest common ancestor of two specified nodes in the tree.

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
    
	if (root == null || root == p || root == q) return root;
	TreeNode left = lowestCommonAncestor(root.left, p, q);
	TreeNode right = lowestCommonAncestor(root.right, p, q);
	// root 左右两边都能找到,分别为 p, q,则 root 是最近公共祖先
	if (left != null && right != null) return root;
	// 只有 root 左边 能找到
	if (left != null) return left;
	// 只有 root 右边 能找到
	if (right != null) return right;
	// 左右都找不到
	return null;
}

The nearest common ancestor of a binary search tree

Topic: 235. The nearest common ancestor of a binary search tree - LeetCode

Given a binary search tree, find the nearest common ancestor of two specified nodes in the tree.

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
    
	// 如果 p, q 值都小于 root, 说明 p, q 在 root 的左子树中
	if (root.val > p.val && root.val > q.val)
		return lowestCommonAncestor(root.left, p, q);
	// 如果 p, q 值都大于 root, 说明 p, q 在 root 的右子树中
	if (root.val < p.val && root.val < q.val)
		return lowestCommonAncestor(root.right, p, q);
	// p, q 分布在 root 左右,则 root 为最近公共祖先
	return root;
}

Insertion operation in binary search tree

Topic: 701. Insertion Operation in Binary Search Tree - LeetCode

Given a binary search tree (BST) root node rootand a value to insert into the tree value, insert the value into the binary search tree. Returns the root node of the binary search tree after insertion. The input data guarantees that the new value is different from any node value in the original binary search tree.

recursion:

public TreeNode insertIntoBST(TreeNode root, int val) {
    
    
	if (root == null) return new TreeNode(val);
	if (root.val > val) root.left = insertIntoBST(root.left, val);
	else root.right = insertIntoBST(root.right, val);
	return root;
}

Iterate:

public TreeNode insertIntoBST(TreeNode root, int val) {
    
    
	if (root == null) return new TreeNode(val);
	TreeNode node = root, parent = root; // 记录上一个节点
	while (node != null) {
    
    
		parent = node;
		if (val > node.val) node = node.right;
		else node = node.left;
	}
	if (val > parent.val) parent.right = new TreeNode(val); 
	else parent.left = new TreeNode(val);
	return root;
}

Delete a node in a binary search tree**

Topic: 450. Delete Nodes in Binary Search Tree - LeetCode

Given a root node root of a binary search tree and a value key , delete the node corresponding to the key in the binary search tree , and ensure that the nature of the binary search tree remains unchanged. Returns a reference to the (possibly updated) root node of the binary search tree.

Three cases of deletion:

  1. Nodes with a degree of 0 (leaf nodes) are deleted directly
  2. Node with degree 1: replace the node with a child node
  3. Node with degree 2: overwrite it with predecessor/successor, delete predecessor/successor
public TreeNode deleteNode(TreeNode root, int key) {
    
    
	if (root == null) return null;
	// 目标值 < 当前节点值, 往左找
	if (root.val > key) root.left = deleteNode(root.left, key);
	// 目标值 > 当前节点值, 往右找
	else if (root.val < key) root.right = deleteNode(root.right, key);
	// 目标值 == 当前节点值, 进行删除操作
	else {
    
    
		// 情况 1: 度为 0 的节点 (叶子节点): 直接删除
		if (root.left == null && root.right == null) return null;
		// 情况 2: 度为 1 的节点: 用子节点替代该节点
		else if (root.right == null) return root.left;
		else if (root.left == null) return root.right;
		// 情况 3: 度为 2 的节点: 用 前驱/后继 覆盖它, 再删除 前驱/后继
		else {
    
    
			// 前驱: 左节点的最右节点
			TreeNode pre = root.left;
			while (pre.right != null) pre = pre.right; // 寻找前驱
			root.val = pre.val; // 用前驱覆盖当前节点
			root.left = deleteNode(root.left, pre.val); // 删除前驱
			
			// 后继: 右节点的最左节点
			// TreeNode suc = root.right;
			// while (suc.left != null) suc = suc.left; // 寻找后继
			// root.val = suc.val; // 用后继覆盖当前节点
			// root.right = deleteNode(root.right, suc.val); // 删除后继
		}
	}
	return root;
}

pruning binary search tree

Title: 669. Pruning a Binary Search Tree - LeetCode

Given the root node of your binary search tree root, you are given a minimum bound lowand a maximum bound high. By pruning the binary search tree, the values ​​of all nodes are in [low, high]. Pruning the tree should not change the relative structure of the elements that remain in the tree (ie, the original parent-child relationship should be preserved if not removed). It can be shown that there is a unique answer .

public TreeNode trimBST(TreeNode root, int low, int high) {
    
    
	if (root == null) return null;
	// root.val < low 则 root.left 下面的节点值都 < low
	if (root.val < low) return trimBST(root.right, low, high);
	// root.val > high 则 root.right 下面的值都 > high
	if (root.val > high) return trimBST(root.left, low, high);
	// 递归调用左右子树
	root.left = trimBST(root.left, low, high);
	root.right = trimBST(root.right, low, high);
	return root;
}

Convert sorted array to binary search tree

Topic: 108. Convert Sorted Array to Binary Search Tree - LeetCode

Given an array of integers numsin which the elements are sorted in ascending , please convert it into a height- balanced binary search tree.

A height-balanced binary tree is a binary tree that satisfies "the absolute value of the height difference between the left and right subtrees of each node does not exceed 1".

Well-understood recursion:

public TreeNode sortedArrayToBST(int[] nums) {
    
    
	if (nums.length == 0) return null;
	int mid = nums.length >> 1;
	TreeNode root = new TreeNode(nums[mid]);
	root.left = sortedArrayToBST(Arrays.copyOfRange(nums, 0, mid));
	root.right = sortedArrayToBST(Arrays.copyOfRange(nums, mid + 1, nums.length));
	return root;
}

Using indexing to optimize the array copy in the recursion above:

class Solution {
    
    
    public TreeNode sortedArrayToBST(int[] nums) {
    
    
        return helper(nums, 0, nums.length - 1);
    }

    TreeNode helper(int[] nums, int l, int r) {
    
    
        if (l > r ) return null;
        int mid = (l + r) >> 1;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, l, mid - 1);
        root.right = helper(nums, mid + 1, r);
        return root;
    }
}

Go Language Documentation

Go's preorder recursive implementation:

func preorderTraversal(root *TreeNode) []int {
    
    
	res := make([]int, 0)
	if root == nil {
    
    
		return res
	}

	st := list.New()
	st.PushBack(root)

	for st.Len() > 0 {
    
    
		node := st.Remove(st.Back()).(*TreeNode)

		res = append(res, node.Val)
		if node.Right != nil {
    
    
			st.PushBack(node.Right)
		}
		if node.Left != nil {
    
    
			st.PushBack(node.Left)
		}
	}
	return res
}

Go's inorder recursive implementation:

// go - 全局变量
var arr []int

func inorderTraversal(root *TreeNode) []int {
    
    
    arr = make([]int, 0)
    dfs(root)
    return arr
}

func dfs(root *TreeNode) {
    
    
    if root != nil {
    
    
        dfs(root.Left)
        arr = append(arr, root.Val)
        dfs(root.Right)
    }
}

// go - 闭包
func inorderTraversal(root *TreeNode) []int {
    
    
    arr := make([]int, 0)
	
    var dfs func(*TreeNode)
    dfs = func(root *TreeNode) {
    
    
        if root == nil {
    
    
            return
        }
        dfs(root.Left)
        arr = append(arr, root.Val)
        dfs(root.Right)
    }
    
    dfs(root)
    return arr
}

// go - 切片当参数传递
func inorderTraversal(root *TreeNode) []int {
    
    
	arr := make([]int, 0)
	dfs(root, &arr)
	return arr
}

func dfs(root *TreeNode, arr *[]int) {
    
    
	if root == nil {
    
    
        return
	}
	dfs(root.Left, arr)
	*arr = append(*arr, root.Val)
	dfs(root.Right, arr)
}

Guess you like

Origin blog.csdn.net/weixin_43734095/article/details/126697337