Tree🌼

Recursive VS. BackTrack

https://blog.csdn.net/ajianyingxiaoqinghan/article/details/79682147

Depth-first traversal

The recursive traversal of a binary tree

In-order traversal (Left-Root-Right):

  1. Traverse the left subtree.
  2. Visit the current node (Root).
  3. Traverse the right subtree.

Pre-order traversal (Root-Left-Right):

  1. Visit the current node (Root).
  2. Traverse the left subtree.
  3. Traverse the right subtree.

Post-order traversal (Left-Right-Root):

  1. Traverse the left subtree.
  2. Traverse the right subtree.
  3. Visit the current node (Root).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 前序遍历·递归·LC144_二叉树的前序遍历
class Solution {
public List<Integer> res = new ArrayList<>();

public List<Integer> preorderTraversal(TreeNode root) {
preT(root);
return res;
}
public void preT(TreeNode root){
if(root == null) return;
res.add(root.val);
preT(root.left);
preT(root.right);
}
}
// 中序遍历·递归·LC94_二叉树的中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root, res);
return res;
}

void inorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
inorder(root.left, list);
list.add(root.val); // 注意这一句
inorder(root.right, list);
}
}
// 后序遍历·递归·LC145_二叉树的后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(root, res);
return res;
}

void postorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
postorder(root.left, list);
postorder(root.right, list);
list.add(root.val); // 注意这一句
}
}

Iterative traversal of a binary tree

  1. Iterative In-order traversal: In this method, we simulate the function call stack of the recursive in-order traversal using a stack data structure. It involves traversing the left subtree first, then visiting the current node, and finally, traversing the right subtree.

    二叉树中序遍历(迭代法)

  2. Iterative Pre-order traversal: In this approach, we use a stack to mimic the recursive pre-order traversal. It involves visiting the current node, then traversing the left subtree, and finally, traversing the right subtree.

    二叉树前序遍历(迭代法)

  3. Iterative Post-order traversal: This method can be a bit more complex than the other two. It requires two stacks or a single stack with additional bookkeeping to simulate the recursive post-order traversal. The nodes are processed in the order of the left subtree, right subtree, and then the current node.

    前序到后序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 前序遍历顺序:中-左-右,入栈顺序:中-右-左
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.right != null){
stack.push(node.right);
}
if (node.left != null){
stack.push(node.left);
}
}
return result;
}
}

// 中序遍历顺序: 左-中-右 入栈顺序: 左-右
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()){
if (cur != null){
// Continuing the traversal of the left nodes
stack.push(cur);
cur = cur.left;
}else{
// reached the end of the root node
// add value into the result
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}

// 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.left != null){
stack.push(node.left);
}
if (node.right != null){
stack.push(node.right);
}
}
Collections.reverse(result);
return result;
}
}

Level-order traversal

  1. 先搞个que,把root加到que里面

  2. while(que的长度不为0)

    记录下que的长度,这就是这一排的元素个数

    挨着把que的元素加到res里面去,加进去一个的同时把这个节点的子节点加入到que里面去。

implement breadth-first traversal (level-order traversal) of a binary tree using a queue.

102二叉树的层序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 102.二叉树的层序遍历
class Solution {
public List<List<Integer>> resList = new ArrayList<List<Integer>>();

public List<List<Integer>> levelOrder(TreeNode root) {
//checkFun01(root,0);
checkFun02(root);

return resList;
}

//DFS--递归方式
public void checkFun01(TreeNode node, Integer deep) {
if (node == null) return;
deep++;

if (resList.size() < deep) {
//当层级增加时,list的Item也增加,利用list的索引值进行层级界定
List<Integer> item = new ArrayList<Integer>();
resList.add(item);
}
resList.get(deep - 1).add(node.val);

checkFun01(node.left, deep);
checkFun01(node.right, deep);
}

//BFS--迭代方式--借助队列
public void checkFun02(TreeNode node) {
if (node == null) return;
Queue<TreeNode> que = new LinkedList<TreeNode>(); //!!!
que.offer(node);

while (!que.isEmpty()) { //!!!!
// new level
List<Integer> itemList = new ArrayList<Integer>(); //!!!!
int len = que.size();

while (len > 0) {
TreeNode tmpNode = que.poll();
itemList.add(tmpNode.val);

if (tmpNode.left != null) que.offer(tmpNode.left);
if (tmpNode.right != null) que.offer(tmpNode.right);
len--;
}

resList.add(itemList);
}

}
}

my version:

  1. Binary Tree Level Order Traversal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public List<List<Integer>> res = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root) {
trav(root);
return res;
}
public void trav(TreeNode node){
if(node == null) return;
Queue<TreeNode> que = new LinkedList<TreeNode>(); // !!!LinkedList, cant be arraylist
que.offer(node);
while(!que.isEmpty()){ //que != null
int num = que.size(); // not length num用来记录每一排有几个元素
List<Integer> itemList = new ArrayList<Integer>();
//itemList 用来记录que里面马上要出来的一排的nodes
while(num != 0){
TreeNode popNode = que.poll();
itemList.add(popNode.val); //准备好itemlist
num--;
if(popNode.left != null){ //把poll出去的节点的子节点offer进来
que.offer(popNode.left);
}
if(popNode.right != null){
que.offer(popNode.right);
}
}

//把itemList给加到res里面
res.add(itemList);
}

}
}

que==null VS. que.isEmpty()

  1. que.isEmpty(): This is a method used to check if the queue is empty or not. The isEmpty() method is available in the java.util.Queue interface and is implemented by classes like LinkedList or PriorityQueue. It returns true if the queue has no elements, and false otherwise.

Here’s an example of how to use isEmpty():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
javaCopy codeimport java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();

// Adding elements to the queue
queue.offer("Element 1");
queue.offer("Element 2");

// Check if the queue is empty
if (queue.isEmpty()) {
System.out.println("Queue is empty.");
} else {
System.out.println("Queue is not empty.");
}
}
}
  1. que == null: This is a comparison that checks whether the reference que points to a valid queue object (i.e., not null). If que is a valid reference to a queue object, the comparison que == null will return false. If que is not pointing to any object (i.e., it is null), then the comparison will return true.

Here’s an example of how to use the que == null comparison:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
javaCopy codeimport java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
public static void main(String[] args) {
Queue<String> queue = null;

// Check if the queue reference is null
if (queue == null) {
System.out.println("Queue reference is null.");
} else {
System.out.println("Queue reference is not null.");
}
}
}

In this example, we initialize the queue variable to null and then use the que == null comparison to check if the reference is null.

Remember that isEmpty() is used to check if the queue has no elements, while que == null is used to check if the reference to the queue object is null.

LinkedList

  1. Initialization: To create an ArrayList, you can use the following syntax:

    1
    2

    ArrayList<Type> listName = new ArrayList<Type>();

    For example:

    1
    2

    ArrayList<Integer> numbers = new ArrayList<Integer>();
  2. Adding Elements: You can add elements to an ArrayList using the add method:

    1
    2
    numbers.add(10);
    numbers.add(20);
  3. Accessing Elements: You can access elements by their index using the get method:

    1
    2

    int element = numbers.get(0); // Retrieves the first element
  4. Removing Elements: You can remove elements by index or by value using the remove method:

    1
    2
    numbers.remove(0); // Removes the first element
    numbers.remove(Integer.valueOf(20)); // Removes the first occurrence of the value 20
  5. Checking Size: You can find the size (number of elements) in an ArrayList using the size method:

    1
    2

    int size = numbers.size();
  6. Checking if Empty: You can check if an ArrayList is empty using the isEmpty method:

    1
    2

    boolean isEmpty = numbers.isEmpty();
  7. Iterating: You can iterate through the elements of an ArrayList using various loops, such as for-each:

    1
    2
    3
    for (Integer number : numbers) {
    System.out.println(number);
    }
  8. Clearing: You can remove all elements from an ArrayList using the clear method:

    1
    2

    numbers.clear();
  9. Checking for Existence: You can check if an element exists in the ArrayList using the contains method:

    1
    2

    boolean contains = numbers.contains(10);
  10. Converting to an Array: You can convert an ArrayList to an array using the toArray method:

    1
    2

    Integer[] numberArray = numbers.toArray(new Integer[0]);
  11. Sorting: You can sort an ArrayList using the Collections.sort method:

    1
    2

    Collections.sort(numbers);

107. Binary Tree Level Order Traversal II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* 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 {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
level(res, root);
for(int i = 0 ; i < res.size()/2; i++){
List<Integer> temp = res.get(i);
res.set( i, res.get(res.size()-i-1)); //notice -1
res.set(res.size() - i -1, temp); //notice -1
}
return res;

/*
List<List<Integer>> result = new ArrayList<>();
for (int i = res.size() - 1; i >= 0; i-- ) {
result.add(res.get(i));
}
*/

}
public void level(List<List<Integer>> res, TreeNode root){
Queue<TreeNode> que = new LinkedList<TreeNode>();
if(root == null){
return;
}
que.offer(root);
while(!que.isEmpty()){
int num = que.size();
List<Integer> level = new ArrayList<>();
while(num > 0){
TreeNode temp = que.poll();
level.add(temp.val);
if(temp.left != null){
que.offer(temp.left);
}
if(temp.right != null){
que.offer(temp.right);
}
num--;
}
res.add(level);
}

}
}


or:
/**
* 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 {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root == null) return res;
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while(!que.isEmpty()){
int num = que.size();
List<Integer> row = new ArrayList<>();
while(num >0){
TreeNode temp = que.poll();
row.add(temp.val);
if(temp.left != null)que.offer(temp.left);
if(temp.right != null)que.offer(temp.right);
num--;
}
res.add(row);
}
Collections.reverse(res);
return res;
}
}

199. Binary Tree Right Side View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public List<Integer> res = new ArrayList<Integer>();

public List<Integer> rightSideView(TreeNode root) {
if( root == null) return res;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.offer(root);

while(!que.isEmpty()){
int num = que.size();
while(num!=0){
TreeNode temp = que.poll();

if(temp.left != null)
que.offer(temp.left);
if(temp.right != null)
que.offer(temp.right);

if(num == 1){
res.add(temp.val);
}

num--; // need to put num-1 after num ==1
}

return res;
}
}

637. Average of Levels in Binary Tree

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<Double>();
if(root == null) return res;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.add(root);
while(!que.isEmpty()){
int num = que.size();
double mark = num;
double sum = 0;
while ( num != 0){
TreeNode temp = que.poll();
sum += temp.val;
num--;
if(temp.left != null) que.add(temp.left);
if(temp.right != null) que.add(temp.right);
}
res.add(sum/mark);

}

return res;
}
}

429. N-ary Tree Level Order Traversal

Given an n-ary tree, return the level order traversal of its nodes’ values.

Nary-Tree input serialization is represented in their level order traversal, each group of children is separated by the null value (See examples).

Example 1:

img

1
2
Input: root = [1,null,3,2,4,null,5,6]
Output: [[1],[3,2,4],[5,6]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {

public List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> levelOrder(Node root) {
if(root == null) return res;
Queue<Node> que = new LinkedList<Node>();
que.add(root);
while(!que.isEmpty()){
int num = que.size();
List<Integer> list = new ArrayList<Integer>();
while(num > 0){
Node temp = que.poll();
list.add(temp.val);
for(Node child: temp.children){ //!!!
que.add(child);
}
num--;
}
res.add(list);
}

return res;
}
}

515. Find Largest Value in Each Tree Row

Given the root of a binary tree, return an array of the largest value in each row of the tree (0-indexed).

Example 1:

img

1
2
Input: root = [1,3,2,5,3,null,9]
Output: [1,3,9]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public List<Integer> res = new ArrayList<Integer>();
public List<Integer> largestValues(TreeNode root) {
if(root == null) return res;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.add(root);
while(!que.isEmpty()){
int num = que.size();

int big = Integer.MIN_VALUE;
while(num > 0){
TreeNode temp = que.poll();

big = Math.max(big, temp.val);
if(temp.left != null) que.add(temp.left);
if(temp.right != null) que.add(temp.right);
num--;
}
res.add(big);
}
return res;
}
}

116. Populating Next Right Pointers in Each Node

You are given a perfect binary tree where all leaves are on the same level, and every parent has two children. The binary tree has the following definition:

1
2
3
4
5
6
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Example 1:

img

1
2
3
Input: root = [1,2,3,4,5,6,7]
Output: [1,#,2,3,#,4,5,6,7,#]
Explanation: Given the above perfect binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B. The serialized output is in level order as connected by the next pointers, with '#' signifying the end of each level.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {

public Node connect(Node root) {
if(root == null) return null;
Queue<Node> que = new LinkedList<Node>();
que.add(root);
while(!que.isEmpty()){
int num = que.size();
Queue<Node> Itemlist = new LinkedList<Node>();
while(num != 0){
Node temp = que.poll();
Itemlist.add(temp);
if(temp.left != null) que.add(temp.left);
if(temp.right != null) que.add(temp.right);

num--;

}
while(Itemlist.size() > 1){ // >1 not >0

Node temp = Itemlist.poll();
Node tempnext = Itemlist.peek(); // cant poll, only peek.

temp.next = tempnext;

}

}
return root;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//second try:

class Solution {
public Node connect(Node root) {
if(root ==null) return root;
Queue<Node> que = new LinkedList<>();
que.add(root);
while(que.size() > 0){
int num = que.size();
List<Node> record = new ArrayList<>();
while(num > 0){
Node temp = que.poll();
if(temp.left!= null) que.add(temp.left);
if(temp.right!= null) que.add(temp.right);
record.add(temp);
num--;
}
if(record.size() == 1){
record.get(0).next = null;
}else{
for( int i = 0 ; i < record.size() - 1; i++){
Node first = record.get(i);
Node second = record.get(i+1);
first.next = second;
}
record.get(record.size() - 1).next = null;
}
}
return root;
}
}

226. Invert Binary Tree

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

Example 1:

img

1
2
Input: root = [4,2,7,1,3,6,9]
Output: [4,7,2,9,6,3,1]

我们来看一下递归三部曲:

  1. 确定递归函数的参数和返回值

参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。

返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为TreeNode*

1
TreeNode* invertTree(TreeNode* root)

2.确定终止条件

当前节点为空的时候,就返回

1
if (root == NULL) return root;

3.确定单层递归的逻辑

因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

1
2
3
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
class Solution {
public TreeNode invertTree(TreeNode root) {
TreeNode node = root;
if(root == null){
return root;
}
swapChildren(root); //preorder
invertTree(root.left);
// cant put swapChildren in the middle
invertTree(root.right);
// swapChildren(root); postorder

return root;
}

public void swapChildren(TreeNode node){
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
}



// this also works
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;
if(root.left != null || root.right != null){
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
if(root.right != null) invertTree(root.right); // the order of here doesn't matter!
if(root.left != null) invertTree(root.left);

return root;

}

}


//BFS
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {return null;}
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
deque.offer(root);
while (!deque.isEmpty()) {
int size = deque.size();
while (size-- > 0) {
TreeNode node = deque.poll();
swap(node);
if (node.left != null) deque.offer(node.left);
if (node.right != null) deque.offer(node.right);
}
}
return root;
}

public void swap(TreeNode root) {
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}

//secodn try:
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;
if(root.left != null && root.right != null){
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
invertTree( root.left );
invertTree( root.right );
}else if(root.right != null && root.left == null){
root.left = root.right;
root.right = null;
invertTree(root.left);
}else{
root.right = root.left;
root.left = null;
invertTree(root.right);
}
return root;
}
}

其实上面那个是等于这样写
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;

TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
invertTree( root.left );
invertTree( root.right );

return root;
}
}

101. Symmetric Tree

Given the root of a binary tree, check whether it is a mirror of itself (i.e., symmetric around its center).

Example :

img

1
2
Input: root = [1,2,2,3,4,4,3]
Output: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
boolean res = compare(root.left,root.right);
return res;
}


boolean compare(TreeNode left, TreeNode right){

if((left != null && right == null) || (left == null && right != null) ){
return false;
}
if(left == null && right == null){
return true;
}
if(left != null && right != null){
if(left.val != right.val){
return false;
}
}
boolean outside = compare(left.left, right.right);
boolean inside = compare(left.right, right.left);
return outside&&inside;

}

}


//second try: wrong
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
if(root.left != null && root.right != null){
if(root.left.val == root.right.val){
isSymmetric(root.left);
isSymmetric(root.right);
}else{
return false;
}
}else if(root.left == null && root.right == null){
return true;
}else{
return false;
}

return true;
}
}

https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0101.%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91.md

  1. 确定递归函数的参数和返回值
1
bool compare(TreeNode* left, TreeNode* right)
  1. 确定终止条件
1
2
3
4
5
6
7
8
9
10
11
if((left != null && right == null) || (left == null && right != null) ){
return false;
}
if(left == null && right == null){
return true;
}
if(left != null && right != null){
if(left.val != right.val){
return false;
}
}
  1. 确定单层递归的逻辑

    1
    2
    3
    boolean outside = compare(left.left, right.right);
    boolean inside = compare(left.right, right.left);
    return outside&&inside;

100. Same Tree

img

1
2
Input: p = [1,2,3], q = [1,2,3]
Output: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) return true;
return compare(p, q);
}

public boolean compare(TreeNode left, TreeNode right){
if (left == null && right == null) return true;
if(left != null && right == null) return false;
if(right != null && left == null) return false;
if(right != null && left != null) {
if(right.val != left.val) return false;
}
boolean leftc = compare(left.left, right.left);
boolean rightc = compare(left.right, right.right);
return leftc&&rightc;
}
return true;

}
}

104. Maximum Depth of Binary Tree

tree’s height VS. tree’s depth:

tutorial: https://www.bilibili.com/video/BV1Gd4y1V75u/?vd_source=7cf01a4cc731f5d6335bce33c114b60c

  • The “depth” of a node is measured from the root to the node.
  • The “height” of a node is measured from the node to a leaf.

高度(👆): 后序遍历 (easier)

深度(👇): 前序遍历

根节点的高度就是二叉树的最大深度

本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)

而根节点的高度就是二叉树的最大深度,所以本题中我们通过后序求的根节点高度来求的二叉树最大深度。

  • WAY1 post-order traversal:
1
2
3
4
5
6
7
8
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left, right) + 1; // 注意要+1, 这是当前节点的高度
}
}
  1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回这棵树的深度,所以返回值为int类型。

代码如下:

1
int getdepth(TreeNode* node)
  1. 确定终止条件:如果为空节点的话,就返回0,表示高度为0。

代码如下:

1
if (node == NULL) return 0;
  1. 确定单层递归的逻辑:先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。

代码如下:

1
2
3
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left, right) + 1;
  • WAY2: 层序遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int layer = 0;
public int maxDepth(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.add(root);
while(!que.isEmpty()){
int num = que.size();
layer++;
while(num != 0){
TreeNode temp = que.poll();
num --;
if(temp.left!=null)que.add(temp.left);
if(temp.right!=null)que.add(temp.right);
}
}
return layer;
}
}
  • WAY3: pre-order traversal:(COMPLICATED, SO HAVENT READ)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class solution {
public:
int result;
void getdepth(TreeNode* node, int depth) {
result = depth > result ? depth : result; // 中

if (node->left == NULL && node->right == NULL) return ;

if (node->left) { // 左
depth++; // 深度+1
getdepth(node->left, depth);
depth--; // 回溯,深度-1
}
if (node->right) { // 右
depth++; // 深度+1
getdepth(node->right, depth);
depth--; // 回溯,深度-1
}
return ;
}
int maxDepth(TreeNode* root) {
result = 0;
if (root == NULL) return result;
getdepth(root, 1);
return result;
}
};


class Solution {
/**
* 递归法(求深度法)
*/
//定义最大深度
int maxnum = 0;

public int maxDepth(TreeNode root) {
ans(root,0);
return maxnum;
}

//递归求解最大深度
void ans(TreeNode tr,int tmp){
if(tr==null) return;
tmp++;
maxnum = maxnum<tmp?tmp:maxnum;
ans(tr.left,tmp);
ans(tr.right,tmp);
tmp--;
}
}

second try: (recursive loop)

1
2
3
4
5
6
7
8
9
10
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
return count(root, 0);
}
public int count(TreeNode node, int level){
if(node == null) return level;
return Math.max(count(node.left, level+1),count(node.right, level+1));
}
}

559. Maximum Depth of N-ary Tree

1
2
3
4
5
6
7
8
9
10
class Solution {
public int maxDepth(Node root) {
if(root == null) return 0;
int max = 0;
for(Node child: root.children){
max = Math.max(max, maxDepth(child));
}
return max+1;
}
}

111. Minimum Depth of Binary Tree

Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

Note: A leaf is a node with no children.

Example :

img

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

最大深度很容易理解,最小深度就不那么好理解,如图:

111.二叉树的最小深度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Solution {
public int minDepth(TreeNode root) {
if(root == null) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
//如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。
//反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 1
if(root.left == null ) !!!!!!!!!!!!
return right + 1; !!!!!!!!!!!!
if(root.right == null ) !!!!!!!!!!!!
return left + 1; !!!!!!!!!!!!
return Math.min(left, right)+1;
}
}



class Solution {
/**
* 迭代法,层序遍历
*/
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
Deque<TreeNode> deque = new LinkedList<>();
deque.offer(root);
int depth = 0;
while (!deque.isEmpty()) {
int size = deque.size();
depth++;
for (int i = 0; i < size; i++) {
TreeNode poll = deque.poll();
if (poll.left == null && poll.right == null) {
// 是叶子结点,直接返回depth,因为从上往下遍历,所以该值就是最小值
return depth;
}
if (poll.left != null) {
deque.offer(poll.left);
}
if (poll.right != null) {
deque.offer(poll.right);
}
}
}
return depth;
}
}

second try:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//wrong:
class Solution {
public int minDepth(TreeNode root) {
if(root == null) return 0;
if(root.left == null) return count(root.right) + 1;
if(root.right == null) return count(root.left) + 1;
return Math.min(count(root.left),count(root.right));
}
public int count(TreeNode node){
if(node == null) return 0;
return Math.min(count(node.left) , count(node.right)) + 1;
}
}

222. Count Complete Tree Nodes

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

According to Wikipedia, every level, except possibly the last, is completely filled in a complete binary tree, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

Design an algorithm that runs in less than O(n) time complexity.

Example 1:

img

1
2
Input: root = [1,2,3,4,5,6]
Output: 6

递归遍历的顺序依然是后序(左右中):

1
2
3
4
5
6
7
8
class Solution {
public int countNodes(TreeNode root) {
if(root == null) return 0;
int left = countNodes(root.left) ;
int right = countNodes(root.right) ;
return left + right + 1;
}
}
    int left = countNodes(root.left)+1 ; 
  
    int right = countNodes(root.right)+1 ;
     
    return left + right;
    
    这样的话,相当于上一层的那个节点被加了两次。
1
2
3
4
5
6
7
8
9
10
//second try wrong:
class Solution {
public int countNodes(TreeNode root) {
if(root == null) return 0;
if(root.left != null) return countNodes(root.left) + 1;
if(root.right != null) return countNodes(root.right) + 1;

return countNodes(root.left) + countNodes(root.right);
}
}

WAY2: COMPLETE BINARY TREE

https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0222.%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E8%8A%82%E7%82%B9%E4%B8%AA%E6%95%B0.md

vedio -> https://www.bilibili.com/video/BV1eW4y1B7pD/?vd_source=7cf01a4cc731f5d6335bce33c114b60c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
/**
* 针对完全二叉树的解法
*
* 满二叉树的结点数为:2^depth - 1
*/
public int countNodes(TreeNode root) {
if (root == null) return 0;
TreeNode left = root.left;
TreeNode right = root.right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
while (left != null) { // 求左子树深度
left = left.left;
leftDepth++;
}
while (right != null) { // 求右子树深度
right = right.right;
rightDepth++;
}
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
}
return countNodes(root.left) + countNodes(root.right) + 1;
}
}

110. Balanced Binary Tree

Given a binary tree, determine if it is height-balanced

Example 1:

img

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

A balanced binary tree, also referred to as a height-balanced binary tree, is defined as a binary tree in which the height of the left and right subtree of any node differ by not more than 1.

wrong version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null) return true;
int min = min(root);
int max = max(root);
if(max - min <= 1) return true;
return false;
}
public int min(TreeNode node){
if(node == null) return 0;
int left = min(node.left);
int right = min(node.right);
return Math.min(left, right) + 1;
}
public int max(TreeNode node){
if(node == null) return 0;
int left = max(node.left);
int right = max(node.right);
return Math.max(left, right) + 1;
}
}

However, there are a few issues with the provided code:

  1. The recursive calls to isBalanced inside the if condition are not returning the result. Instead, they are being called, but the result is not being used or returned.
  2. The calculation of height in the methods countLef and countRig seems incorrect, as it simply returns the count of nodes in the left and right subtrees, respectively, rather than the height of the subtrees.

right version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// class Solution {
// public boolean isBalanced(TreeNode root) {
// if(root == null) return true;

// if(countLef(root) - countRig(root) <= 1) {
// isBalanced(root.left);
// isBalanced(root.right);
// }else{
// return false;
// }
// return true;

// }
// public int countLef(TreeNode node){
// if(node == null) return 0;
// int left = countLef(node.left);
// return left + 1;
// }
// public int countRig(TreeNode node){
// if(node == null) return 0;
// int right = countRig(node.right);
// return right + 1;
// }

// }

class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) {
return true;
}

int leftHeight = height(root.left);
int rightHeight = height(root.right);

if (Math.abs(leftHeight - rightHeight) <= 1) {
// Check if both left and right subtrees are balanced
return isBalanced(root.left) && isBalanced(root.right); !!!!!!!!!!!!
} else {
return false;
}
}

public int height(TreeNode node) {
if (node == null) {
return 0;
}

// Compute the height of the left and right subtrees
int leftHeight = height(node.left);
int rightHeight = height(node.right);

// Return the maximum height plus 1 (to account for the current node)
return Math.max(leftHeight, rightHeight) + 1;
}
}

!!!!!!!!!!!!!!!!!!!!!!104!!!!!!!!在104.二叉树的最大深度中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

递归

此时大家应该明白了既然要求比较高度,必然是要后序遍历

递归三步曲分析:

  1. 明确递归函数的参数和返回值

参数:当前传入节点。 返回值:以当前传入节点为根节点的树的高度。

那么如何标记左右子树是否差值大于1呢?

如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。

所以如果已经不是二叉平衡树了,可以返回-1 来标记已经不符合平衡树的规则了。

代码如下:

1
2
// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
int getHeight(TreeNode* node)
  1. 明确终止条件

递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0

代码如下:

1
2
3
if (node == NULL) {
return 0;
}
  1. 明确单层递归的逻辑

如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。

分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
int leftHeight = getHeight(node->left); // 左
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right); // 右
if (rightHeight == -1) return -1;

int result;
if (abs(leftHeight - rightHeight) > 1) { // 中
result = -1;
} else {
result = 1 + max(leftHeight, rightHeight); // 以当前节点为根节点的树的最大高度
}

return result;

代码精简之后如下:

1
2
3
4
5
int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);

此时递归的函数就已经写出来了,这个递归的函数传入节点指针,返回以该节点为根节点的二叉树的高度,如果不是二叉平衡树,则返回-1。

getHeight整体代码如下:

1
2
3
4
5
6
7
8
9
10
int getHeight(TreeNode* node) {
if (node == NULL) {
return 0;
}
int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1;
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
}

最后本题整体递归代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
/**
* 递归法
*/
public boolean isBalanced(TreeNode root) {
return getHeight(root) != -1;
}

private int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
int leftHeight = getHeight(root.left);
if (leftHeight == -1) {
return -1;
}
int rightHeight = getHeight(root.right);
if (rightHeight == -1) {
return -1;
}
// 左右子树高度差大于1,return -1表示已经不是平衡树了
if (Math.abs(leftHeight - rightHeight) > 1) {
return -1;
}
return Math.max(leftHeight, rightHeight) + 1;
}
}

257. Binary Tree Paths

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

A leaf is a node with no children.

Example 1:

img

1
2
Input: root = [1,2,3,null,5]
Output: ["1->2->5","1->3"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class Solution {

List<String> res = new ArrayList<>();

public List<String> binaryTreePaths(TreeNode root) {
deal(root, "");
return res;
}

public void deal(TreeNode node, String s) {
if(node == null ) return ;
if(node.left == null && node.right == null){
res.add(s + Integer.toString(node.val));
return;
}
String tmp = s + Integer.toString(node.val)+"->";
deal(node.left,tmp);
deal(node.right, tmp);
}
}
//////////////////////////////////////////////////////////

class Solution {

List<String> result = new ArrayList<>();

public List<String> binaryTreePaths(TreeNode root) {
deal(root, "");
return result;
}

public void deal(TreeNode node, String s) {
if (node == null)
return;
if (node.left == null && node.right == null) {
result.add(new StringBuilder(s).append(node.val).toString());
//toString method converts StringBuider into String type.
return;
}
String tmp = new StringBuilder(s).append(node.val).append("->").toString();
deal(node.left, tmp);
deal(node.right, tmp);
}
}

//second try:
class Solution {
public List<String> res = new ArrayList<>();
public List<String> binaryTreePaths(TreeNode root) {
if(root == null) return res;
findPath(root, String.valueOf(root.val));
return res;

}
public void findPath(TreeNode node, String path){
// if(node == null){
// res.add(path);
// return;
// } //!!!!!!!!!!notice where went wrong

if (node.left == null && node.right == null) {
// Leaf node, add the path to the result
res.add(path);
return;
}

if(node.left != null){
findPath(node.left, path+ "->" + node.left.val);
}
if(node.right != null){
findPath(node.right, path+ "->" + node.right.val);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//回溯算法(原始算法,精简之前的代码)较难
class Solution {
/**
* 递归法
*/
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();// 存最终的结果
if (root == null) {
return res;
}
List<Integer> paths = new ArrayList<>();// 作为结果中的路径
traversal(root, paths, res);
return res;
}

private void traversal(TreeNode root, List<Integer> paths, List<String> res) {
paths.add(root.val);// 前序遍历,中
// 遇到叶子结点
if (root.left == null && root.right == null) {
// 输出
StringBuilder sb = new StringBuilder();// StringBuilder用来拼接字符串,速度更快
for (int i = 0; i < paths.size() - 1; i++) {
sb.append(paths.get(i)).append("->");
}
sb.append(paths.get(paths.size() - 1));// 记录最后一个节点
res.add(sb.toString());// 收集一个路径
return;
}
// 递归和回溯是同时进行,所以要放在同一个花括号里
if (root.left != null) { // 左
traversal(root.left, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
if (root.right != null) { // 右
traversal(root.right, paths, res);
paths.remove(paths.size() - 1);// 回溯
}
}
}

404. Sum of Left Leaves

判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。

如果该节点的左节点不为空,该节点的左节点的左节点为空,该节点的左节点的右节点为空,则找到了一个左叶子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) { //是指root以下的节点,满足要求的sum
if (root == NULL) return 0;
if (root->left == NULL && root->right== NULL) return 0;
//是因为root.left 和root.right以下的子节点的sumofleftleaves=0.不包括本层的。
int leftValue = sumOfLeftLeaves(root->left); // 左
if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
leftValue = root->left->val;
}
int rightValue = sumOfLeftLeaves(root->right); // 右

int sum = leftValue + rightValue; // 中
return sum;
}
};


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

public void sum(TreeNode node){
if (node == null) { //not node.left right == null !!!!!!!!!!!!!!!!!!!
return; // Return if the current node is null
} !!!!!!!!!!!!!!!!!!!
if(node.left != null && node.left.left == null && node.left.right == null){
res += node.left.val;
}
sum(node.left);
sum(node.right);
}
}

递归三部曲:

  1. 确定递归函数的参数和返回值

判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int

使用题目中给出的函数就可以了。

  1. 确定终止条件

如果遍历到空节点,那么左叶子值一定是0

1
if (root == NULL) return 0;

注意,只有当前遍历的节点是父节点,才能判断其子节点是不是左叶子。 所以如果当前遍历的节点是叶子节点,那其左叶子也必定是0,那么终止条件为:

1
2
if (root == NULL) return 0;
if (root->left == NULL && root->right== NULL) return 0; //其实这个也可以不写,如果不写不影响结果,但就会让递归多进行了一层。
  1. 确定单层递归的逻辑

当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
second try:

class Solution {
int sum = 0;
public int sumOfLeftLeaves(TreeNode root) {
sum(root);
return sum;
}
public void sum( TreeNode node ){
if(node == null) return;

if(node.left != null && node.left.left == null && node.left.right == null) sum += node.left.val;

if(node.left != null) sum(node.left);
if(node.right != null) sum(node.right);
}
}

513. Find Bottom Left Tree Value

Given the root of a binary tree, return the leftmost value in the last row of the tree.

Example :

img

1
2
Input: root = [1,2,3,4,null,5,6,null,null,7]
Output: 7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
recursive method :

class Solution {
public int res = 0;
public int maxDep = -1; // not 0
public int findBottomLeftValue(TreeNode root) {
if(root == null) return 0;
findLeft(root, 0);
return res;
}
public void findLeft(TreeNode node, int depth){
if(node == null) return;
if(node.left == null && node.right == null){

if(depth > maxDep){
maxDep = depth;
res = node.val;
}
}
depth++;
if (node.left != null)findLeft(node.left,depth + 1); // 隐藏着回溯
if (node.right != null)findLeft(node.right,depth + 1); //notice not depth++
}
}



class Solution {
int res = 0;
int maxdepth = -1;
public int findBottomLeftValue(TreeNode root) {
find(root,0);
return res;
}
public void find(TreeNode root, int depth){
if(root == null) return;
if(root.left == null && root.right == null){
if(depth > maxdepth){
res = root.val;
maxdepth = depth;
}
}
if(root.left != null){
depth ++;
find(root.left, depth);
depth--;
}
if(root.right != null){
depth ++;
find(root.right, depth);
depth--;
}


}

}

iterative method: (my version)
// find the first node in the last row of the tree
class Solution {
public int res;
public int findBottomLeftValue(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.add(root);
while(! que.isEmpty()){
int num = que.size();
for(int i = 0; i < num; i++){

TreeNode temp = que.poll();
if(i == 0) res = temp.val;
if(temp.left != null) que.add(temp.left);
if(temp.right != null) que.add(temp.right);
}
}
return res;
}


112. Path Sum

Given the root of a binary tree and an integer targetSum, return true if the tree has a root-to-leaf path such that adding up all the values along the path equals targetSum.

A leaf is a node with no children.

Example 1:

img

1
2
3
Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
Output: true
Explanation: The root-to-leaf path with the target sum is shown.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public boolean res = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
check(root, targetSum, 0);
return res;
}
public void check(TreeNode node, int targetSum, int sum){
if(node == null) return;
sum += node.val;
if(node.left == null && node.right == null){
if(targetSum == sum) res = true;
}else{
check(node.left, targetSum, sum);
check(node.right, targetSum, sum);
}

}
}

2.确定终止条件

首先计数器如何统计这一条路径的和呢?

不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。

如果最后count == 0,同时到了叶子节点的话,说明找到了目标和。

如果遍历到了叶子节点,count不为0,就是没找到。

递归终止条件代码如下:

1
2
if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
if (!cur->left && !cur->right) return false; // 遇到叶子节点而没有找到合适的边,直接返回

3.确定单层递归的逻辑

因为终止条件是判断叶子节点,所以递归的过程中就不要让空节点进入递归了。

递归函数是有返回值的,如果递归函数返回true,说明找到了合适的路径,应该立刻返回。

代码如下:

1
2
3
4
5
6
7
8
9
if (cur->left) { // 左 (空节点不遍历)
// 遇到叶子节点返回true,则直接返回true
if (traversal(cur->left, count - cur->left->val)) return true; // 注意这里有回溯的逻辑
}
if (cur->right) { // 右 (空节点不遍历)
// 遇到叶子节点返回true,则直接返回true
if (traversal(cur->right, count - cur->right->val)) return true; // 注意这里有回溯的逻辑
}
return false;

以上代码中是包含着回溯的,没有回溯,如何后撤重新找另一条路径呢。

回溯隐藏在traversal(cur->left, count - cur->left->val)这里, 因为把count - cur->left->val 直接作为参数传进去,函数结束,count的数值没有改变。

为了把回溯的过程体现出来,可以改为如下代码:

1
2
3
4
5
6
7
8
9
10
11
if (cur->left) { // 左
count -= cur->left->val; // 递归,处理节点;
if (traversal(cur->left, count)) return true;
count += cur->left->val; // 回溯,撤销处理结果
}
if (cur->right) { // 右
count -= cur->right->val;
if (traversal(cur->right, count)) return true;
count += cur->right->val;
}
return false;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// second try:  time out
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
return count(root, targetSum, 0);
}
public boolean count(TreeNode node, int target, int sum){
if(node == null) return false;
if(node.left == null && node.right == null) { //leaf
sum += node.val;
if(sum == target) return true;
else return false;
}

if(node.left != null) count(node.left, target, sum + node.val);
if(node.right != null) count(node.right, target, sum + node.val);
//return false; this is wrong !!!!!!!!!!!!!
//In the provided code, the return false; statement is placed at the end of the count method. This statement will always be executed regardless of the conditions above it.
return count(node.left, target, sum + node.val) || count(node.right, target, sum + node.val);
}
}

// modify:
//1:
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
return count(root, targetSum, 0);
}
public boolean count(TreeNode node, int target, int sum){
if(node == null) return false;
if(node.left == null && node.right == null) { //leaf
sum += node.val;
if(sum == target) return true;
else return false;
}
boolean left = false;
boolean right = false;
if(node.left != null) left = count(node.left, target, sum + node.val); //!!!!!!!!!!!
if(node.right != null) right = count(node.right, target, sum + node.val);//!!!!!!!!!!!!!

return left || right;
}
}


//2:
class Solution {
public boolean res = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
count(root, targetSum, 0);
return res;
}
public void count(TreeNode node, int target, int sum){ //!!!!!!!!!! void
if(node == null) return;
if(node.left == null && node.right == null) { //leaf
sum += node.val;
if(sum == target) res = true;

}

if(node.left != null) count(node.left, target, sum + node.val);
if(node.right != null) count(node.right, target, sum + node.val);
//return false;
//return count(node.left, target, sum + node.val) || count(node.right, target, sum + node.val);
}
}

106. Construct Binary Tree from Inorder and Postorder Traversal

Given two integer arrays inorder and postorder where inorder is the inorder traversal of a binary tree and postorder is the postorder traversal of the same tree, construct and return the binary tree.

Example :

img

1
2
Input: inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
Output: [3,9,20,null,null,15,7]

https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0106.%E4%BB%8E%E4%B8%AD%E5%BA%8F%E4%B8%8E%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91.md

  • 第一步:如果数组大小为零的话,说明是空节点了。
  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
  • 第五步:切割后序数组,切成后序左数组和后序右数组
  • 第六步:递归处理左区间和右区间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
private TreeNode traversal(int[] inorder, int inorderBegin, int inorderEnd, int[] postorder, int postorderBegin, int postorderEnd) {
if (postorderBegin == postorderEnd) return null;
// find middle node in postorder 后序遍历数组最后一个元素,就是当前的中间节点
int rootValue = postorder[postorderEnd - 1];
TreeNode root = new TreeNode(rootValue);
// leaf node
if (postorderEnd - postorderBegin == 0) return root;
// find middle node in the inorder
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 递归处理左区间和右区间
//用中序中左区间的大小可以去切后续的左区间

// 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + (delimiterIndex - inorderBegin);
// 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
int rightPostorderEnd = postorderEnd - 1;

root.left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
root.right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);

return root;
}

public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder.length == 0 || postorder.length == 0) return null;
// 左闭右开的原则
return traversal(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
}

105. Construct Binary Tree from Preorder and Inorder Traversal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length == 0 || inorder.length ==0) return null;
return construct(preorder, 0, preorder.length, inorder, 0, inorder.length);
}
public TreeNode construct(int[] pre, int pres, int pree, int[]in, int ins, int ine){
if (pres == pree) return null; // Base case

int midValue = pre[pres];
TreeNode mid = new TreeNode(midValue);
//mid.val = pre[pres];
if(pres - pree == 0) return mid;

int index;

for(index = ins; index < ine; index++ ){
if(in[index] == midValue) break;
}

int leftPreStart = pres + 1;
int leftPreEnd = pres + 1 + index - ins ;
int rightPreStart = pres + 1 + index - ins;
int rightPreEnd = pree;

int leftInStart = ins;
int leftInEnd = index;
int rightInStart = index + 1;
int rightInEnd = ine;
mid.left = construct(pre, leftPreStart, leftPreEnd, in, leftInStart, leftInEnd);
mid.right = construct(pre, rightPreStart, rightPreEnd, in, rightInStart, rightInEnd);
return mid;
}
}

654. Maximum Binary Tree

Medium

You are given an integer array nums with no duplicates. A maximum binary tree can be built recursively from nums using the following algorithm:

  1. Create a root node whose value is the maximum value in nums.
  2. Recursively build the left subtree on the subarray prefix to the left of the maximum value.
  3. Recursively build the right subtree on the **subarray suffix ** to the right of the maximum value.

Return the maximum binary tree built from nums.

Example 1:

img

1
2
3
4
5
6
7
8
9
10
11
12
Input: nums = [3,2,1,6,0,5]
Output: [6,3,5,null,2,0,null,null,1]
Explanation: The recursive calls are as follow:
- The largest value in [3,2,1,6,0,5] is 6. Left prefix is [3,2,1] and right suffix is [0,5].
- The largest value in [3,2,1] is 3. Left prefix is [] and right suffix is [2,1].
- Empty array, so no child.
- The largest value in [2,1] is 2. Left prefix is [] and right suffix is [1].
- Empty array, so no child.
- Only one element, so child is a node with value 1.
- The largest value in [0,5] is 5. Left prefix is [0] and right suffix is [].
- Only one element, so child is a node with value 0.
- Empty array, so no child.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
if(nums.length == 0) return null;
return cons(nums, 0, nums.length);
}

public TreeNode cons(int[] nums, int start, int end){
if(end - start < 1) return null; // 没元素了!!!
if(end - start == 1) return new TreeNode(nums[start]); //只有一个元素(左闭右开)!!!
TreeNode root = new TreeNode();
int max = nums[start];
int index = start;
for( int i = start; i < end; i++){
if (max < nums[i]){
max = nums[i];
index = i;
}
}
root.val = max;
root.left = cons(nums, start, index);
root.right = cons(nums, index+1, end);
return root;
}

}
//second try:
//left close right close
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return build(nums, 0 , nums.length -1);
}
public TreeNode build(int[] nums, int begin, int end){
if(begin > end) return null; //!!!!
int max = nums[begin];
int index = begin;
for(int i = begin ; i <= end; i++){
if(nums[i] > max){
index = i;
max = nums[i];
}
}
TreeNode root = new TreeNode(max);
root.left = build(nums, begin, index -1);
root.right = build(nums, index + 1, end);

return root;
}
}

wrong version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
//if(nums.length == 0) return null;
return cons(nums, 0, nums.length);
}

public TreeNode cons(int[] nums, int start, int end){
// if(end - start < 1) return null; // 没元素了
// if(end - start == 1) return new TreeNode(nums[start]); //只有一个元素 leaf node
TreeNode root = new TreeNode();
if(end == start ) return root;
int max = nums[start];
int index = start;
for( int i = start; i < end; i++){
if (max < nums[i]){
max = nums[i];
index = i;
}
}
root.val = max;
root.left = cons(nums, start, index);
root.right = cons(nums, index+1, end);
return root;
}

617. Merge Two Binary Trees

Easy

You are given two binary trees root1 and root2.

Imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. You need to merge the two trees into a new binary tree. The merge rule is that if two nodes overlap, then sum node values up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of the new tree.

Return the merged tree.

Note: The merging process must start from the root nodes of both trees.

Example 1:

img

1
2
Input: root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
Output: [3,4,5,5,4,null,7]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null && root2 == null) {
return null;
}

TreeNode root = new TreeNode();

if (root1 == null) {
root.val = root2.val;
} else if (root2 == null) {
root.val = root1.val;
} else {
root.val = root1.val + root2.val;
}

root.left = mergeTrees(root1 != null ? root1.left : null, root2 != null ? root2.left : null);
root.right = mergeTrees(root1 != null ? root1.right : null, root2 != null ? root2.right : null);

return root;
}
}


//leetcoke:
class Solution {
// 递归
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) return root2; //!!!!!!
if (root2 == null) return root1; //!!!!!!!!

root1.val += root2.val;
root1.left = mergeTrees(root1.left,root2.left);
root1.right = mergeTrees(root1.right,root2.right);
return root1;
}
}

// second try: fail
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null && root2 == null ) return root1;;
if(root1.left != null && root2.left != null){
root1.val = root1.val + root2.val;
}
}
}

700. Search in a Binary Search Tree

You are given the root of a binary search tree (BST) and an integer val.

Find the node in the BST that the node’s value equals val and return the subtree rooted with that node. If such a node does not exist, return null.

Example 1:

img

1
2
Input: root = [4,2,7,1,3], val = 2
Output: [2,1,3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null) return root;
if(root.val == val) return root;
TreeNode result = new TreeNode();
result = searchBST(root.left, val);
if(result != null ) return result;
result = searchBST(root.right, val);
return result;
}
}


WRONG:
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null) return root;
if(root.val == val) return root;

searchBST(root.left, val);
searchBST(root.right, val);
return null;
}
}

//second try:
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if(root == null) return null;
if(root.val == val) return root;
if(val < root.val && root.left != null) return searchBST(root.left,val);
if(val > root.val && root.right != null)
return searchBST(root.right,val);
return null;
}
}


整体代码如下:

1
2
3
4
5
6
7
8
9
10
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if (root == NULL || root->val == val) return root;
TreeNode* result = NULL; //!!!!!!!!!!!!!!!!!!!!!!
if (root->val > val) result = searchBST(root->left, val);
if (root->val < val) result = searchBST(root->right, val);
return result;
}
};

或者我们也可以这么写

1
2
3
4
5
6
7
8
9
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if (root == NULL || root->val == val) return root;
if (root->val > val) return searchBST(root->left, val);
if (root->val < val) return searchBST(root->right, val);
return NULL;
}
};

98. Validate Binary Search Tree

Given the root of a binary tree, determine if it is a valid binary search tree (BST).

A valid BST is defined as follows:

  • The left subtree

    of a node contains only nodes with keys

    less than

    the node’s key.

  • The right subtree of a node contains only nodes with keys greater than the node’s key.

  • Both the left and right subtrees must also be binary search trees.

Example 1:

img

1
2
Input: root = [2,1,3]
Output: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
实质上就是中序遍历
class Solution {
public TreeNode max;
public boolean isValidBST(TreeNode root) {
if (root == null) return true;

boolean left = isValidBST(root.left); //左
if(!left) return false;

if (max != null && root.val <= max.val) { //中 比较节点的逻辑
return false;
}
max = root; //记录当前节点的上一个节点,因为按照中序遍历,当前节点都应该比上一个节点大。

boolean right = isValidBST(root.right);//右
if(!right) return false;


return true;
}
}

// my
class Solution {

public TreeNode max;
public boolean isValidBST(TreeNode root) {
boolean left = true;
boolean right = true;
if(root.left != null)
left = isValidBST(root.left);

if(max!= null && root.val <= max.val){
return false;
}
max = root;

if(root.right != null)
right = isValidBST(root.right);

return left && right;

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

class Solution {
public List<Integer> res = new ArrayList<>();
public boolean isValidBST(TreeNode root) {
see(root);
return check(res);
}
public void see(TreeNode node){
if(node == null) return;
see(node.left);
res.add(node.val);
see(node.right);
}
public boolean check(List<Integer> res){
for(int i = 0; i < res.size() - 1; i++){
if(res.get(i) >= res.get(i+1)) return false;
//!!!! >= not >
}
return true;
}
}

530. Minimum Absolute Difference in BST

Given the root of a Binary Search Tree (BST), return the minimum absolute difference between the values of any two different nodes in the tree.

Example :

img

1
2
Input: root = [4,2,6,1,3]
Output: 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
mine:
class Solution {
public List<Integer> res = new ArrayList<Integer>();
public int min = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if(root == null) return 0;
inorder(root);
check(res);
return min;
}
public void inorder(TreeNode node){
if(node == null) return;
inorder(node.left);
res.add(node.val);
inorder(node.right);
}
public void check(List<Integer> res){
for(int i = 0; i < res.size() - 1; i++){
int temp = res.get(i+1) - res.get(i);
if(temp < min){
min = temp;
}
}
}
}

//SECOND TRY:
class Solution {
Integer pre;
int dif = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if(root == null) return dif;
getMinimumDifference(root.left);
if(pre != null ){
int temp = Math.abs(pre - root.val);
if(dif > temp) dif = temp;
}
pre = root.val;
getMinimumDifference(root.right);
return dif;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
leetcode:
// 双指针

class Solution {
TreeNode pre;// 记录上一个遍历的结点
int result = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if(root==null)return 0;
traversal(root);
return result;
}
public void traversal(TreeNode root){
if(root==null)return;
//左
traversal(root.left);
//中
if(pre!=null){
result = Math.min(result,root.val-pre.val);
}
pre = root;
//右
traversal(root.right);
}
}

501. Find Mode in Binary Search Tree

Given the root of a binary search tree (BST) with duplicates, return all the mode(s) (i.e., the most frequently occurred element) in it.

If the tree has more than one mode, return them in any order.

Assume a BST is defined as follows:

  • The left subtree of a node contains only nodes with keys less than or equal to the node’s key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
  • Both the left and right subtrees must also be binary search trees.

Example 1:

img

1
2
Input: root = [1,null,2,2]
Output: [2]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
MY VERSION:
class Solution {
public HashMap<Integer, Integer> map = new HashMap<>();
public int count = 0;
public List<Integer> res = new ArrayList<Integer>();
public int[] findMode(TreeNode root) {
find(root);
for (Map.Entry<Integer, Integer> entry : map.entrySet()){ !!!!!!!!!!!!!!!!!!
int temp = entry.getValue();
if (count < temp) {
count = temp;
}
}

for (Map.Entry<Integer, Integer> entry : map.entrySet()){ !!!!!!!!!!!!!!!!!!!!!!
if (entry.getValue() == count) {
res.add(entry.getKey());
}
}
return res.stream().mapToInt(Integer::intValue).toArray(); !!!!!!!!!!!!!!!!!!!

//or

// Convert ArrayList to array (for primitive types)
//int[] array = new int[res.size()];
//for (int i = 0; i < res.size(); i++) {
// array[i] = res.get(i);
//}

return array;
}
public void find(TreeNode node){
if(node == null) return;
find(node.left);
map.put(node.val, map.getOrDefault(node.val,0)+1);
find(node.right);
}
}

双指针:
class Solution {
ArrayList<Integer> resList;
int maxCount;
int count;
TreeNode pre;

public int[] findMode(TreeNode root) {
resList = new ArrayList<>();
maxCount = 0;
count = 0;
pre = null;
findMode1(root);
int[] res = new int[resList.size()]; !!!!!!!!!!!!
for (int i = 0; i < resList.size(); i++) {
res[i] = resList.get(i);
}
return res;
}

public void findMode1(TreeNode root) {
if (root == null) {
return;
}
findMode1(root.left);

int rootValue = root.val;
// 计数
if (pre == null || rootValue != pre.val) {
count = 1;
} else {
count++;
}
// 更新结果以及maxCount
if (count > maxCount) {
resList.clear();
resList.add(rootValue);
maxCount = count;
} else if (count == maxCount) {
resList.add(rootValue);
}
pre = root;

findMode1(root.right);
}
}

哈希表:
class Solution {
public int[] findMode(TreeNode root) {
Map<Integer, Integer> map = new HashMap<>();
List<Integer> list = new ArrayList<>();
if (root == null) return list.stream().mapToInt(Integer::intValue).toArray();
// 获得频率 Map
searchBST(root, map);
List<Map.Entry<Integer, Integer>> mapList = map.entrySet().stream()
.sorted((c1, c2) -> c2.getValue().compareTo(c1.getValue()))
.collect(Collectors.toList());
list.add(mapList.get(0).getKey());
// 把频率最高的加入 list
for (int i = 1; i < mapList.size(); i++) {
if (mapList.get(i).getValue() == mapList.get(i - 1).getValue()) {
list.add(mapList.get(i).getKey());
} else {
break;
}
}
return list.stream().mapToInt(Integer::intValue).toArray();
}

void searchBST(TreeNode curr, Map<Integer, Integer> map) {
if (curr == null) return;
map.put(curr.val, map.getOrDefault(curr.val, 0) + 1);
searchBST(curr.left, map);
searchBST(curr.right, map);
}

}

236. Lowest Common Ancestor of a Binary Tree

https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0236.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88.md

再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

  • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
  • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Example 1:

img

1
2
3
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The LCA of nodes 5 and 1 is 3.
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return null;
if(root == p || root == q) return root; //网上返回 !!!!!!!!!
TreeNode left = lowestCommonAncestor(root.left , p, q);
TreeNode right = lowestCommonAncestor(root.right , p, q);
if(left == null && right == null) return null;
if(left == null && right != null) return right;
if(left != null && right == null) return left;
if(left != null && right != null) return root; //!!!!!!!!!!!
return root;
}
}

首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。 即情况一:

img

判断逻辑是 如果递归遍历遇到q,就将q返回,遇到p 就将p返回,那么如果 左右子树的返回值都不为空,说明此时的中节点,一定是q 和p 的最近祖先。

那么有录友可能疑惑,会不会左子树 遇到q 返回,右子树也遇到q返回,这样并没有找到 q 和p的最近祖先。

这么想的录友,要审题了,题目强调:二叉树节点数值是不重复的,而且一定存在 q 和 p

但是很多人容易忽略一个情况,就是节点本身p(q),它拥有一个子孙节点q(p)。 情况二:

其实情况一 和 情况二 代码实现过程都是一样的,也可以说,实现情况一的逻辑,顺便包含了情况二。

因为遇到 q 或者 p 就返回,这样也包含了 q 或者 p 本身就是 公共祖先的情况。

这一点是很多录友容易忽略的

if dont understand here, check the video.

236.二叉树的最近公共祖先1

图中节点10的左子树返回null,右子树返回目标值7,那么此时节点10的处理逻辑就是把右子树的返回值(最近公共祖先7)返回上去!

这里也很重要,可能刷过这道题目的同学,都不清楚结果究竟是如何从底层一层一层传到头结点的。

那么如果left和right都为空,则返回left或者right都是可以的,也就是返回空

那么我给大家归纳如下三点

  1. 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
  2. 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
  3. 要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。

可以说这里每一步,都是有难度的,都需要对二叉树,递归和回溯有一定的理解。

本题没有给出迭代法,因为迭代法不适合模拟回溯的过程。理解递归的解法就够了。

235. Lowest Common Ancestor of a Binary Search Tree

Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Example 1:

img

1
2
3
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null ) return null;
if(root.val > p .val && root.val > q.val){
TreeNode left = lowestCommonAncestor(root.left, p, q);
if(left != null) return left;
}
if(root.val < p .val && root.val < q.val){
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(right != null) return right;
}
return root;
}
}

you can also use the method in 236 as well.

二叉树:公共祖先问题中,如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树。

搜索一条边的写法:

1
2
if (递归函数(root->left)) return ;
if (递归函数(root->right)) return ;

搜索整个树写法:

1
2
3
left = 递归函数(root->left);
right = 递归函数(root->right);
left与right的逻辑处理;

本题就是标准的搜索一条边的写法,遇到递归函数的返回值,如果不为空,立刻返回。

701. Insert into a Binary Search Tree

看代码随想录!!!!!!!!!

Medium

You are given the root node of a binary search tree (BST) and a value to insert into the tree. Return the root node of the BST after the insertion. It is guaranteed that the new value does not exist in the original BST.

Notice that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion. You can return any of them.

Example :

img

1
2
3
Input: root = [4,2,7,1,3], val = 5
Output: [4,2,7,1,3,5]
Explanation: Another accepted tree is:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public int rep = 0;
public TreeNode pre;
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null) return new TreeNode(val);//遇到叶子节点,new新节点,并返回上去,返回给上一层
if(root.val > val)
root.left = insertIntoBST(root.left, val);
if(root.val < val)
root.right = insertIntoBST(root.right, val);
return root;
}

}
  • 701.二叉搜索树中的插入操作

    例如插入元素10 ,需要找到末尾节点插入便可,一样的道理来插入元素15,插入元素0,插入元素6,需要调整二叉树的结构么? 并不需要。

    只要遍历二叉搜索树,找到空节点 插入元素就可以了,那么这道题其实就简单了。

    接下来就是遍历二叉搜索树的过程了。

  • 确定终止条件

终止条件就是找到遍历的节点为null的时候,就是要插入节点的位置了,并把插入的节点返回。

代码如下:

1
2
3
4
if (root == NULL) {
TreeNode* node = new TreeNode(val);
return node;
}

这里把添加的节点返回给上一层,就完成了父子节点的赋值操作了,详细再往下看。

  • 确定单层递归的逻辑

此时要明确,需要遍历整棵树么?

别忘了这是搜索树,遍历整棵搜索树简直是对搜索树的侮辱,哈哈。

搜索树是有方向了,可以根据插入元素的数值,决定递归方向。

代码如下:

1
2
3
if (root->val > val) root->left = insertIntoBST(root->left, val);
if (root->val < val) root->right = insertIntoBST(root->right, val);
return root;

有返回值的话,可以利用返回值完成新加入的节点与其父节点的赋值操作

到这里,大家应该能感受到,如何通过递归函数返回值完成了新加入节点的父子关系赋值操作了,下一层将加入节点返回,本层用root->left或者root->right将其接住

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

// with return

class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (root == NULL) {
TreeNode* node = new TreeNode(val);
return node;
}
if (root->val > val) root->left = insertIntoBST(root->left, val);
if (root->val < val) root->right = insertIntoBST(root->right, val);
return root;
}
};


////////////////////////////////////

//without return

class Solution {
private:
TreeNode* parent;
void traversal(TreeNode* cur, int val) {
if (cur == NULL) {
TreeNode* node = new TreeNode(val);
if (val > parent->val) parent->right = node;
else parent->left = node;
return;
}
parent = cur;
if (cur->val > val) traversal(cur->left, val);
if (cur->val < val) traversal(cur->right, val);
return;
}

public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
parent = new TreeNode(0);
if (root == NULL) {
root = new TreeNode(val);
}
traversal(root, val);
return root;
}
};

450. Delete Node in a BST

Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.

Basically, the deletion can be divided into two stages:

  1. Search for a node to remove.
  2. If the node is found, delete the node.

Example 1:

img

1
2
3
4
5
Input: root = [5,3,6,2,4,null,7], key = 3
Output: [5,4,6,2,null,null,7]
Explanation: Given key to delete is 3. So we find the node with value 3 and delete it.
One valid answer is [5,4,6,2,null,null,7], shown in the above BST.
Please notice that another valid answer is [5,2,6,null,4,null,7] and it's also accepted.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return null;
if(root.val == key){

if(root.left == null && root.right == null){
return null; // not return
}
if(root.right != null && root.left == null ){
return root.right;
}
if(root.left != null && root.right == null ){
return root.left;
}
if(root.left != null && root.right != null){
// !!!!!!!!!!!!!!!!!!!!!
TreeNode temp = root.right;
while(temp.left != null){
temp = temp.left;
}
temp.left = root.left;
return root.right;
}
}
if(key < root.val)
root.left = deleteNode(root.left, key);
if(key > root.val)
root.right = deleteNode(root.right, key); //右子树接住删除完节点的子树
return root;


}
}

669. Trim a Binary Search Tree

Given the root of a binary search tree and the lowest and highest boundaries as low and high, trim the tree so that all its elements lies in [low, high]. Trimming the tree should not change the relative structure of the elements that will remain in the tree (i.e., any node’s descendant should remain a descendant). It can be proven that there is a unique answer.

Return the root of the trimmed binary search tree. Note that the root may change depending on the given bounds.

Example :

img

1
2
Input: root = [1,0,2], low = 1, high = 2
Output: [1,null,2]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null) return null;
if(root.val < low){ // abandone left tree
TreeNode right = trimBST(root.right, low, high);
return right;
}
if(root.val > high){ // abandone right tree
TreeNode left = trimBST(root.left, low, high);
return left;
}
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
}



/**
* 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 {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null) return null;




if(root.val < low){
// root.left = null;
// if(root.right != null){
// root = root.right;
// }
//return root.right;
root.right = trimBST(root.right, low, high);
return root.right;
}
if(root.val > high){
// root.right = null;
// if(root.left != null){
// root = root.left;
// }
//return root.left;
root.left = trimBST(root.left, low, high);
return trimBST(root.left, low, high);
}

root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);

return root;
}
}

108. Convert Sorted Array to Binary Search Tree

Given an integer array nums where the elements are sorted in ascending order, convert it to a

*height-balanced*

binary search tree.

Example:

img

1
2
3
Input: nums = [-10,-3,0,5,9]
Output: [0,-3,9,-10,null,5]
Explanation: [0,-10,5,null,-3,null,9] is also accepted:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return create(nums, 0 , nums.length ); // 左闭右开 Closed on the left, open on the right
}

public TreeNode create(int[] nums, int left, int right){
if(left >= right) return null; // it's >= not >
int mid = (right - left) / 2 + left;
TreeNode root = new TreeNode(nums[mid]);
root.left = create(nums, left, mid );
root.right = create(nums, mid + 1, right );
return root;
}
}

//wrong:
class Solution {
TreeNode res;
public TreeNode sortedArrayToBST(int[] nums) {

build(nums, 0, nums.length - 1, res);
return res;

}
public void build(int[] nums, int start,int end, TreeNode res){
if(start > end) return;
res = new TreeNode(nums[(start + end) / 2]);
build(nums, start, (start + end) / 2 - 1, res.left);
build(nums, (start + end) / 2 + 1, end, res.right);

}
}

538. Convert BST to Greater Tree

Medium

Given the root of a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus the sum of all keys greater than the original key in BST.

As a reminder, a binary search tree is a tree that satisfies these constraints:

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than the node’s key.
  • Both the left and right subtrees must also be binary search trees.

Example 1:

img

1
2
Input: root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
Output: [30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

!!! right mid left !!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
int res = 0;
public TreeNode convertBST(TreeNode root) {
if(root == null) return null;

if(root.right != null) convertBST(root.right);
res += root.val;
root.val = res;

if(root.left != null) convertBST(root.left);
return root;
}
}


//wrong version:
class Solution {
public TreeNode pre = new TreeNode(0);
public TreeNode convertBST(TreeNode root) {
if(root == null) return root;
convertBST(root.right);
root.val += pre.val;
convertBST(root.left); //
pre.val = root.val;
return root;
}
}

114. Flatten Binary Tree to Linked List

Medium

Given the root of a binary tree, flatten the tree into a “linked list”:

  • The “linked list” should use the same TreeNode class where the right child pointer points to the next node in the list and the left child pointer is always null.
  • The “linked list” should be in the same order as a pre-order traversal of the binary tree.

Example 1:

img

1
2
Input: root = [1,2,5,3,4,null,6]
Output: [1,null,2,null,3,null,4,null,5,null,6]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Solution {
public void flatten(TreeNode root) {
if (root == null) {
return;
}
flattenTree(root);
}

private TreeNode flattenTree(TreeNode node) {
if (node == null) {
return null;
}

// Recursively flatten the left and right subtrees
TreeNode leftTail = flattenTree(node.left);
TreeNode rightTail = flattenTree(node.right);

// Store the right subtree to link it later
TreeNode rightSubtree = node.right;

// If there's a left subtree, move it to the right
if (node.left != null) {
node.right = node.left;
node.left = null;
}

// Connect the right subtree after the newly moved left subtree
if (leftTail != null) {
leftTail.right = rightSubtree;
}

// Return the rightmost node after flattening
return (rightTail != null) ? rightTail : (leftTail != null) ? leftTail : node;
}
}

​ 1

/
2 5
/ \
3 4 6

Step 1:
1
/
2

Step 2:
1
/
2

3

Step 3:
1

2

3

Step 4:
1

2

3

4

Step 5:
1

2

3

4

5

Step 6:
1

2

3

4

5

6

[toc]