PHPer interview must see: take you to “sword finger offer” binary tree

Time:2021-6-14

Opening

The following content may be exam oriented, but it’s easy to understand, so we must insist on it, because we are doomed to be lonely in the process of becoming stronger. If we insist on it, we will see the sun of tomorrow.

review

PHPer interview must see: take you to

Let’s move onLet’s talk about the binary tree you understandThis article comes from. Let’s quickly review the concepts related to binary trees

  • Degree: the total number of children of a particular parent node is called its degree.
  • Path: the sequence of nodes and edges from the source node to the target node is called the path between two nodes.
  • Node height: the height of a node is determined by the number of edges between the node and the deepest node.
  • Tree height: the height of a tree is defined by the height of its root node.
  • Depth: the depth of a node is determined by the number of edges between the node and the root node.

There are also concepts related to binary tree classification

  • Binary search tree: binary search tree (BST) is a special type of binary tree, in which nodes are stored in order, that is, at any given point, the node value must be greater than or equal to the left child node value and less than the right child node value.
  • Self balanced binary tree: self balanced binary search tree or height balanced binary search tree is a special type of binary search tree, which tries to keep the height or level of the tree as small as possible through automatic adjustment.

Common types of balanced binary trees are as follows:

  • AA tree
  • AVL tree
  • Red black tree

If you don’t understand these basic contents, you can go to the article mentioned at the beginning to see the details.

warm-up

Let’s not talk too much. Let’s take a look at the first topic about tree in sword finger offer.

Input the result of preorder traversal and meso traversal of a binary tree, please rebuild the binary tree. Assume that the results of preorder traversal and meso traversal do not contain duplicate numbers. For example, if the preorder traversal sequence {1,2,4,7,3,5,6,8} and the middle order traversal sequence {4,7,2,1,5,3,8,6} are input, the binary tree is reconstructed and returned.

Thinking analysis: according to the characteristics of binary tree preorder traversal (root left right), the first value read each time must be the root node, so we can find the current root node position in the sequence of preorder traversal.

According to the characteristics of middle order traversal (left root right), when a root node is determined, the left sequence is the left subtree of the root node, and the right sequence is the right subtree.

Every time we need to find the root node in the preorder traversal and create a root node, and then determine the location of the root node in the preorder traversal, and determine the left and right subtrees of the current root node, and then construct the left and right subtrees in the same way.

This is a recursive process. What is recursion? Don’t panic, not clear students can see what I wrote beforeWhat is recursionBe sure to understand the recursion, because the following topics will be a lot of use of the idea of recursion.

Let’s look at the specific code implementation

/*class TreeNode{
    var $val;
    var $left = NULL;
    var $right = NULL;
    function __construct($val){
        $this->val = $val;
    }
}*/

function reConstructBinaryTree($pre, $vin)
{
    if (empty($pre) || empty($vin)) {
        return null;
    }
    //Find the root node in the preorder
    $root = new TreeNode($pre[0]);
    //Determine the position of the root node in the middle order traversal
    $indexInVin = array_search($pre[0], $vin, true);
    //The result of left subtree preorder traversal
    $leftPrev = array_slice($pre, 1, $indexInVin); 
    //Results of middle order traversal in left subtree
    $leftVin = array_slice($vin, 0, $indexInVin); 
    //The result of traversing the right subtree in order
    $rightPrev = array_slice($pre, $indexInVin + 1);
    //Results of middle order traversal in right subtree
    $rightVin = array_slice($vin, $indexInVin + 1);
    //Recursive tree building
    $root->left = reConstructBinaryTree($leftPrev, $leftVin);
    $root->right = reConstructBinaryTree($rightPrev, $rightVin);
    //Return to root node
    return $root;
}

Complete code inhere, students in need can click to view.

OK, let’s go on. Look at the second one.

Input two binary trees a and B to judge whether B is the substructure of A( PS: we agree that an empty tree is not a substructure of any tree.)

Thinking analysis: in the first case, if the root nodes are the same, then go to the child nodes to match. If not, look
In the second case, if the root node is different, compare the left child of proot1 with proot2. If not, try to compare the right child of proot1 with proot2.

Or the use of recursion, see the following answer.

/*class TreeNode{
    var $val;
    var $left = NULL;
    var $right = NULL;
    function __construct($val){
        $this->val = $val;
    }
}*/
function HasSubtree($pRoot1, $pRoot2)
{
    if (empty($pRoot1) || empty($pRoot2)) {
        return false;
    }
    return isSubtree($pRoot1, $pRoot2) || HasSubtree($pRoot1->left, $pRoot2)
    || HasSubtree($pRoot1->right, $pRoot2);
}
function isSubtree($pRoot1, $pRoot2)
{
    if (empty($pRoot2)) {
        return true;
    }
    if (empty($pRoot1)) {
        return false;
    }
    return $pRoot1->val === $pRoot2->val && isSubtree($pRoot1->left, $pRoot2->left) && isSubtree($pRoot1->right, $pRoot2->right);
}

Let’s look at the next one.

Operate the given binary tree and transform it into the mirror image of the source binary tree.

This topic is very famous. Maybe you often see it. But it’s not hard, 10 lines of code. Still want to use the idea of recursion, look at the code to understand.

<?php
/*class TreeNode{
    var $val;
    var $left = NULL;
    var $right = NULL;
    function __construct($val){
        $this->val = $val;
    }
}*/
//https://www.zhihu.com/question/31202353?rf=31230953
//Operate the given binary tree and transform it into the mirror image of the source binary tree.
function Mirror(&$root)
{
    if (empty($root)) {
        return;
    }
    $left = $root->left;
    $right = $root->right;
    $root->right = $left;
    $root->left = $right;
    Mirror($root->left);
    Mirror($root->right);
}

Next, let’s look at a topic about traversing binary tree hierarchically. In addition to traversing binary tree hierarchically, we should also master itPreorder, middle order, recursive algorithm and non recursive algorithm of traversing binary treeIn addition, there are common operations such as node search, add and deletehereIt’s too late.

Each node of the binary tree is printed from top to bottom, and the nodes of the same layer are printed from left to right.

Thinking analysis: we need to establish a queue, first the root node into the queue, and then the team first out of the queue, and then judge whether its left and right subtree is empty, if not, first the left subtree into the queue, and then the right subtree into the queue.

function PrintFromTopToBottom($root)
{
    $traverse = [];
    array_push($traverse, $root->val);
    inQueue($root, $traverse);
    return $traverse;
}
function inQueue($node, &$return)
{
    if (empty($node)) {
        return;
    }
    if ($left = $node->left) {
        array_push($return, $left->val);
    }
    if ($right = $node->right) {
        array_push($return, $right->val);
    }
    inQueue($left, $return);
    inQueue($right, $return);
}

There is also a non recursive solution to this problem. ClickhereYou can see the source code.

Congratulations, you insist on seeing here, great! We continue.

There is a similar variant in “sword finger offer”, which is the following one, zigzag traversing binary tree.

Please implement a function to print the binary tree according to zigzag, that is, the first line is printed from left to right, the second layer is printed from right to left, the third line is printed from left to right, and so on.

Thinking analysis: when we print the node of a line, we save the node of the next layer to the corresponding stack. If the current printed layer is odd, save the left child node first, and then save the right child node to a stack; If the current printed layer is even, save the right child node first, and then save the left child node to another stack.

/*class TreeNode{
    var $val;
    var $left = NULL;
    var $right = NULL;
    function __construct($val){
        $this->val = $val;
    }
}*/

function MyPrint($pRoot)
{
    if (empty($pRoot)) return [];
    $cur = 0;
    $next = 1;
    $stack[0] = [];
    $stack[1] = [];
    array_push($stack[0], $pRoot);
    $i = 0;
    $return = [];
    $return[0] = [];
    while (!empty($stack[$cur]) || !empty($stack[$next])) {
        $top = array_pop($stack[$cur]);
        array_push($return[$i], $top->val);
        if ($cur == 0) {
            if ($left = $top->left) {
                array_push($stack[$next], $left);
            }
            if ($right = $top->right) {
                array_push($stack[$next], $right);
            }
        } else {
            if ($right = $top->right) {
                array_push($stack[$next], $right);
            }
            if ($left = $top->left) {
                array_push($stack[$next], $left);
            }
        }
        if (empty($stack[$cur])) {
            $cur = 1 - $cur;
            $next = 1 - $next;
            if (!empty($stack[0]) || !empty($stack[1])) {
                $i++;
                $return[$i] = [];
            }
        }
    }
    return $return;
}

Well, now old fellow iron, you can go to have a drink and have a rest, because there are still many questions waiting for us. If you are tired, you can mark them first and go on to see them tomorrow. In addition, click the source codehereLook, old fellow iron can also be star for a while, and later on, your star is the driving force for my renewal.

continue

Input an integer array to judge whether the array is the result of the sequential traversal of a binary search tree. If yes, output yes; otherwise, output No. Suppose that any two numbers of the input array are different from each other.

Thinking analysis: the legal sequence of BST’s postorder sequence is that for a sequence s, the last element is x (that is, the root). If the sequence of removing the last element is t, then t can be divided into two segments, the former segment (left subtree) is less than x, the latter segment (right subtree) is greater than x, and these two segments (subtrees) are legal postorder sequences. Perfect recursive definition.

function VerifySquenceOfBST($sequence)
{
    if (count($sequence) == 0) return false;
    if (count($sequence) == 1) return true;
    
    if ($sequence) {
        $length = count($sequence);
        
         if ($length == 2) {
            if ($sequence[0] < $sequence[1]) return true;
        }
        
        $root = $sequence[$length - 1];
        $left = [];
        $right = [];
        $leftFlag = false;
        $rightFlag = false;
        $i = 0;
        while($sequence[$i] < $root) {
            array_push($left, $sequence[$i]);
            $i++;
        }
        $i === count($left) && $leftFlag = true;
        $j = $i;
        while($sequence[$j] > $root) {
             array_push($right, $sequence[$j]);
             $j++;
        }
        ($j === ($length - 1)) && $rightFlag = true;
        if ($leftFlag && $rightFlag) {
            if ($left && $right) {
                return VerifySquenceOfBST($left) && VerifySquenceOfBST($right);
            } elseif ($left) {
                return VerifySquenceOfBST($left);
            } else {
                return VerifySquenceOfBST($right);
            }
        } else {
            return false;
        }
    }
    return true;
}

Enter the following node and an integer of a binary tree, and print out all paths where the sum of node values in the binary tree is the input integer. Path is defined as a path from the root node to the leaf node( Note: in the list of return values, the array with large array length is the first one

Train of thought analysis: use recursion to traverse all paths.

/*class TreeNode{
    var $val;
    var $left = NULL;
    var $right = NULL;
    function __construct($val){
        $this->val = $val;
    }
}*/
function FindPath($root, $expectNumber)
{
    if (empty($root)) return [];
    $a = $q = [];
    buildPath($root, $expectNumber, $q, $a);
    return $a;
}
function buildPath($node, $sum, $q, &$a)
{
    if ($node) {
        $q[] = $node->val;
        $sum -= $node->val;
        if ($sum > 0) {
            buildPath($node->left, $sum, $q, $a);
            buildPath($node->right, $sum, $q, $a);
        } elseif (empty($node->left) && empty($node->right) && $sum == 0) {
            $a[] = $q;
        }
    }
}

Input a binary search tree, the binary search tree into a sort of two-way list. It is required that no new node can be created, only the pointer of the node in the tree can be adjusted.

Thinking analysis: Method 1: recursive version

  • 1. Construct the left subtree into a double linked list and return the chain header node.
  • 2. Locate to the last node of the left subtree double linked list.
  • 3. If the left subtree list is not empty, append the current root to the left subtree list.
  • 4. Construct the right subtree into a double linked list and return the chain header node.
  • 5. If the right subtree list is not empty, append the list to the root node.
  • 6. Determine the returned node according to whether the left subtree list is empty.
function Convert($pRootOfTree)
{
    // write code here
    if (empty($pRootOfTree)) {
        return null;
    }
    if (empty($pRootOfTree->left) && empty($pRootOfTree->right)) {
        return $pRootOfTree;
    }
    //The left subtree is constructed into a double linked list, and the chain header node is returned.
    $left = Convert($pRootOfTree->left);
    $temp = $left;
    //2. Locate to the last node of the left subtree double linked list.
    while($temp !== null && $temp->right != null) {
        $temp = $temp->right;
    }
    //3. If the left subtree list is not empty, append the current root to the left subtree list.
    if ($left != null) {
        $temp->right = $pRootOfTree;
        $pRootOfTree->left = $temp;
    }
    //4. Construct the right subtree into a double linked list and return the chain header node.
    $right = Convert($pRootOfTree->right);
    //5. If the right subtree list is not empty, append the list to the root node.
    if ($right != null) {
        $right->left = $pRootOfTree;
        $pRootOfTree->right = $right;
    }
    return $left != null ? $left : $pRootOfTree;
}

non-recursive algorithm
How to solve the problem:

  • 1. The core is the non recursive algorithm of middle order traversal (yes, the middle order traversal algorithm mentioned above).
  • 2. Modify the pointer between the current traversal node and the previous traversal node.
function ConvertNotRecursive($pRootOfTree)
{
    if (empty($pRootOfTree)) {
        return null;
    }
    $stack = new \SplStack();
    $p = $pRootOfTree;
    //Used to save the previous node of the middle order traversal sequence
    $pre = null;
    $isFirst = true;
    
    while ($p || !$stack->isEmpty()) {
        while($p) {
            $stack->push($p);
            $p = $p->left;
        }
        $p = $stack->pop();
        if ($isFirst) {
            //Mark the first node in the middle traversal sequence as root
            $pRootOfTree = $p;
            $pre = $pRootOfTree;
            $isFirst = false;
        } else {
            $pre->right = $p;
            $p->left = $pre;
            $pre = $p;
        }
        $p = $p->right;
    }
    return $pRootOfTree;
}

Input a binary tree to judge whether it is a balanced binary tree.

Thinking analysis: the most direct way is to traverse each node, with the help of a recursive function to get the depth of the tree, according to the height difference between the left and right subtrees of the node to judge whether it is balanced, and then recursively judge the left and right subtrees.

function IsBalanced_Solution($pRoot)
{
    if (empty($pRoot)) return true;
    return abs(maxDepth($pRoot->left) - maxDepth($pRoot->right)) <= 1 &&
        IsBalanced_Solution($pRoot->left) && IsBalanced_Solution($pRoot->right);
}
function maxDepth($node)
{
    if (empty($node)) return 0;
    return 1 + max(maxDepth($node->left), maxDepth($node->right));
}

Given a binary tree and one of its nodes, find the next node in the middle order traversal order and return. Note that the nodes in the tree contain not only the left and right child nodes, but also the pointer to the parent node.

Thinking analysis: the next node of the binary tree has the following situations:

  • 1. If the binary tree is empty, null is returned;
  • 2. If the right child of the node exists, set a pointer to start from the right child of the node and follow the pointer to the left child to find the leaf node, which is the next node;
  • 3. The node is not the root node. If the node is the left child of its parent node, the parent node is returned; Otherwise, continue to traverse the parent node of its parent node upward, repeat the previous judgment, and return the result.
function GetNext($pNode)
{
    if (empty($pNode)) return null;
    if ($right = $pNode->right) {
        $currentNode = $right;
        while ($currentNode->left) {
            $currentNode = $currentNode->left;
        }
        return $currentNode;
    }
    
    while ($pNode->next) {
        $parent = $pNode->next;
        if ($parent->left === $pNode) {
            return $parent;
        }
        $pNode = $pNode->next;
    }
    return null;
}

Please implement a function to determine whether a binary tree is symmetric. Note that if a binary tree is the same as its mirror image, it is defined as symmetric.

Thinking analysis: first of all, the root node and its left and right subtrees, the left subtree of the left subtree is the same as the right subtree of the right subtree, and the right subtree of the left subtree is the same as the left subtree of the right subtree. Non recursion can also be used, stack or queue access at all levels of subtree root node.

function isSymmetrical($pRoot)
{
    // write code here
    if (empty($pRoot)) return true;
    
    return compare($pRoot->left, $pRoot->right);
}
function compare($left, $right)
{
    if ($left === null) return $right === null;
    if ($right === null) return false;
    if ($left->val != $right->val) return false;
    return compare($left->right, $right->left) && compare($left->left, $right->right);
}

We can see that recursion is powerful, and when it is used properly, it can get twice the result with half the effort. Finally, the following two topics respectively use the binary tree preorder and middle order traversal algorithm.

Please implement two functions to serialize and deserialize the binary tree

/*class TreeNode{
    var $val;
    var $left = NULL;
    var $right = NULL;
    function __construct($val){
        $this->val = $val;
    }
}*/
function MySerialize($pRoot)
{
    $arr = [];
    doSerialize($pRoot, $arr);
    return implode(',', $arr);
}
function doSerialize($pRoot, &$arr)
{
    if (empty($pRoot)) {
        $arr[] = '#';
        return;
    }
    $arr[] = $pRoot->val;
    doSerialize($pRoot->left, $arr);
    doSerialize($pRoot->right, $arr);
}
function MyDeserialize($s)
{
    $arr = explode(',', $s);
    $i = -1;
    return doDeserialize($arr, $i); 
}
function doDeserialize($arr, &$i)
{
    $i++;
    if ($i >= count($arr)) {
        return null;
    }
    if ($arr[$i] == '#') return null;
    $node = new TreeNode($arr[$i]);
    $node->left = doDeserialize($arr, $i);
    $node->right = doDeserialize($arr, $i);
    return $node;
}

Given a binary search tree, find the kth smallest node. For example, in (5, 3, 7, 2, 4, 6, 8), the value of the third node is 4.

/*class TreeNode{
    var $val;
    var $left = NULL;
    var $right = NULL;
    function __construct($val){
        $this->val = $val;
    }
}*/
function KthNode($pRoot, $k)
{
    $traverse = inOrderTraverse($pRoot);
    if ($k <= count($traverse)) {
        return $traverse[$k - 1];
    }
    return null;
}
function inOrderTraverse($pRoot)
{
    $traverse = [];
    if ($left = $pRoot->left) {
        $traverse = array_merge($traverse, inOrderTraverse($left));
    }
    array_push($traverse, $pRoot);
    if ($right = $pRoot->right) {
        $traverse = array_merge($traverse, inOrderTraverse($right));
    }
    return $traverse;
}

Complete content

PHP basic data structure thematic series directory address:addressMainly use PHP syntax to summarize the basic data structure and algorithm. There are also some basic knowledge that is easy to ignore in our daily PHP development and some practical suggestions on specification, deployment and Optimization in modern PHP development, as well as in-depth study on the characteristics of JavaScript language.

Recommended Today

What is “hybrid cloud”?

In this paper, we define the concept of “hybrid cloud”, explain four different cloud deployment models of hybrid cloud, and deeply analyze the industrial trend of hybrid cloud through a series of data and charts. 01 introduction Hybrid cloud is a computing environment that integrates multiple platforms and data centers. Generally speaking, hybrid cloud is […]