Some problem solving ideas and templates of binary tree

Posted by drakkon on Mon, 24 Jan 2022 14:06:49 +0100

Complete binary tree

concept

A complete binary tree can have no right subtree and no left subtree.

Problem solving ideas

Judge whether it is a complete binary tree: using the sequence traversal method, if it is found that there is right or left, or the first left and right nodes are not complete, the subsequent nodes must be leaf nodes, otherwise it is not a complete binary tree.

Binary search tree (BST)

concept

Binary search tree (BST): the left subtree data of each node is smaller than the node data, and the right subtree is larger than the node data

Problem solving ideas

Judge whether it is a binary search tree: medium order traversal, and the array must be an ascending array.

Full binary tree

concept

Full binary tree: all nodes have left and right subtrees except leaf nodes.

Problem solving ideas

Judge whether it is a full binary tree: first count the maximum depth l of the tree, and then count the number of nodes N of the tree. If N = 2^L - 1, it is a full binary tree

balanced binary tree

concept

Balanced binary tree: it is an empty tree or the absolute value of the height difference between the left and right subtrees does not exceed 1, and both the left and right subtrees are a balanced binary tree.

Problem solving ideas

Take the JZ79 judgment of sword finger offer as an example. According to the concept, first write a function to solve the depth, and then write the judgment conditions: 1. The empty tree is also a balanced binary tree, which returns true. 2. The absolute value of the height difference between the left and right subtrees shall not exceed 1. Finally, because each subtree is a balanced binary tree rather than just from the root node, it is also necessary to recursively IsBalanced_Solution this method.

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function IsBalanced_Solution(pRoot)
{
    // write code here
    function depth(r){
        if(r === null){
            return 0
        }
        return Math.max(depth(r.left),depth(r.right)) + 1
    }
    if(pRoot === null){
        return true
    }
    return Math.abs(depth(pRoot.left) - depth(pRoot.right)) <= 1 && IsBalanced_Solution(pRoot.left) && IsBalanced_Solution(pRoot.right)
}
module.exports = {
    IsBalanced_Solution : IsBalanced_Solution
};

Symmetric binary tree

concept

Symmetric binary tree: a tree with the root node as the axis of symmetry and the left and right subtrees as the axis of symmetry.

Problem solving ideas

Take JZ28 symmetric binary tree of sword finger offer as an example. The method of sequence traversal is used for judgment. First, prepare a queue and queue the root node twice (because it needs to be compared twice each time, and it needs to be out of the queue twice when leaving the queue). Judge twice each time: 1. Whether it is empty. If yes, skip this cycle. 2. Judge whether two of the teams appear and one does not exist (because it is a symmetric binary tree). 3. Judge whether the two values are the same. If they are different, return false directly. Then join the team in the order of queue push(a.left); queue. push(b.right); queue. push(a.right); queue. push(b.left); (because after leaving the team, you need to compare its value in pairs)

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function isSymmetrical(pRoot)
{
    // write code here
    if(pRoot === null){
        return true
    }
    let queue = []
    
    queue.push(pRoot)
    queue.push(pRoot)
    while(queue.length !== 0){
        let a = queue.shift()
        let b = queue.shift()
        if(a === null && b === null){
            continue
        }
        if((!a && b) || (!b && a)){
            return false
        }
        if(a.val !== b.val){
            return false
        }
        queue.push(a.left)
        queue.push(b.right)
        queue.push(a.right)
        queue.push(b.left)
    }
    return true
}
module.exports = {
    isSymmetrical : isSymmetrical
};

Binary tree traversal (recursive template)

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */

// Preorder traversal 
let res = []
function print(tree){
	if(tree === null){
		return 
	}
	res.push(tree)
	print(tree.left)
	print(tree.right)
}

// Medium order traversal
let res = []
function print(tree){
	if(tree === null){
		return 
	}
	print(tree.left)
	res.push(tree)
	print(tree.right)
}

// Postorder traversal
let res = []
function print(tree){
	if(tree === null){
		return 
	}
	print(tree.left)
	print(tree.right)
	res.push(tree)
}

Binary tree traversal (non recursive template)

Preorder traversal

Algorithm steps:
1. Put the header on the stack first
2. Pop a node from the stack
3. Print (process) cur
4. Right then left (if any)
5. Until there are no elements in the stack

if(root !== null){
    let s1 = []
    let s2 = []
    s1.push(root)
    while(s1.length !== 0){
        let root = s1.pop()
        s2.push(root.val)
        if(root.right !== null){
            s1.push(root.right)
        }
        if(root.left !== null){
            s1.push(root.left)
        }
    }
    return s2;
}
return []

Postorder traversal

Algorithm steps:
1. Put the header on the stack first
2. Pop up a node cur from the stack
3. Put cur into collection stack
4. Left then right
5. Until there is no element in the stack, print the out of stack order of the collection stack, that is, post order traversal

if(root !== null){
    let s1 = []
    let s2 = []
    s1.push(root)
    while(s1.length !== 0){
        root = s1.pop()
        s2.push(root.val)
        if(root.left !== null){
            s1.push(root.left)
        }
        if(root.right !== null){
            s1.push(root.right)
        }
    }
    return s2.reverse();
}
return []

Medium order traversal

Problem solving idea: stack from the root node to the left until it is empty, get out of the stack and record it as root, and then go to the right subtree of the root and continue to the left.

if(root !== null){
    let stack = []
    let s = []
    while(stack.length !== 0 || root !== null){
        if(root != null){
            stack.push(root)
            root = root.left
        } else{
            root = stack.pop()
            s.push(root.val)
            root = root.right
        }
    }
    return s
}
return []

level traversal

Problem solving idea: prepare a queue. First join the root node in the queue and cycle out of the queue once each time, and then join the left and right nodes of the out of the queue node. Finally, the order of out of the queue is the order of sequence traversal.

if(root === null){
    return 
} 
let queue = []
queue.push(head)
while(queue.length !== 0){
    let cur = queue.shift()
    console.log(cur)
    if(cur.left !== null){
        queue.push(cur.left)
    }
    if(cur.right !== null){
        queue.push(cur)
    }
}

Topics: data structure leetcode