Leetcode depth first algorithm tree (tree transformation)

Time:2022-6-20

The following five exercises are to use DFS to solve the problem of mutual conversion between array or linked list and binary tree. Unified processing can effectively enhance learning and consolidate memory.

105. constructing binary trees from preorder and inorder traversal sequences

Title Description

According to the preorder traversal and inorder traversal of a tree, a binary tree is constructed.

be careful:
You can assume that there are no duplicate elements in the tree.

For example, give

Preorder traversal = [3,9,20,15,7]
Middle order traversal inorder = [9,3,15,20,7]
The following binary tree is returned:

    3
   / \
  9  20
    /  \
   15   7

thinking

First, if you want to solve this problem, you should first know the characteristics of preorder and inorder traversal. The characteristics of preorder traversal are left to right, that is, the first element of the array is the value of the root node of the whole tree, while the characteristics of preorder traversal are left to right, that is, the nodes of the left subtree are on the left side of the root node, and the right subtree is on the right side of the root node.

According to the above characteristics, we can build a binary tree according to the traversal sequence of pre order + middle order.

  • Find the root node of the tree in the preorder traversal sequence
  • Find this root node in the middle order sequence
  • Then recursively construct subtrees

Since we use recursion to construct subtrees, we need to clarify several conditions of recursion

  • End condition of recursion
  • Recursive sequential structure

The first is the end condition of recursion. We construct the tree according to the tree traversal results, so we can determine the recursion condition according to the traversal array

if (instart == inEnd || preStart == preEnd) return;

The second is the recursive sequential structure. Since we can determine the position of the root node, and then we can find its corresponding left and right subtrees, this situation is to determine the node first and then recurse, which is similar to the preorder traversal.

ensure the root node;
recursion left;
recursion right;

In addition, we can use map to cache the traversal results of the middle order sequence to avoid repeated traversal and use space for time.

code implementation

class Solution {
    
    private Map<Integer, Integer> map = new HashMap<>();
    
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        
        int index = 0;
        for (int cur : inorder) {
            map.put(cur, index++);
        }

        return build(preorder, inorder, 0, preorder.length, 0, inorder.length);
    }

    TreeNode build(int[] pre, int[] in, int pStart, int pEnd, int inStart, int inEnd) {
        if (pStart == pEnd) return null;
        
        int rootVal = pre[pStart];
        int rootIndex = map.get(rootVal);

        TreeNode root = new TreeNode(rootVal);
        int leftNum = rootIndex - inStart;

        root.left = build(pre, in, pStart + 1, pStart + 1 + leftNum, inStart, rootIndex);
        root.right = build(pre, in, pStart + 1 + leftNum, pEnd, rootIndex + 1, inEnd);

        return root;

    }
}

106. construct binary tree from middle order and post order traversal sequence

Title Description

According to the middle order traversal and post order traversal of a tree, a binary tree is constructed.

be careful:
You can assume that there are no duplicate elements in the tree.

For example, give

Middle order traversal inorder = [9,3,15,20,7]
Postorder traversal postorder = [9,15,7,20,3]
The following binary tree is returned:

    3
   / \
  9  20
    /  \
   15   7

thinking

This question is basically similar to question 105 above, without much difference. The root node of post order traversal is the last element of the array. The bounds of the array are left open and right closed.

code

class Solution {

    Map<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        
        int index = 0;
        for (int cur : inorder) {
            map.put(cur, index++);
        }

        return build(inorder, postorder, 0, inorder.length, 0, postorder.length);
    }

    TreeNode build(int[] in, int[] post,int iStart, int iEnd, int pStart, int pEnd) {
        if (iStart == iEnd || pStart == pEnd) return null;

        int rootVal = post[pEnd - 1];
        TreeNode root = new TreeNode(rootVal);

        int rootIndex = map.get(rootVal);
        int leftNum = rootIndex - iStart;

        root.left = build(in, post, iStart, rootIndex, pStart, pStart + leftNum);
        root.right = build(in, post, rootIndex + 1, iEnd, pStart + leftNum, pEnd - 1);

        return root;
    }
}

108. convert an ordered array to a binary search tree

Title Description

An ordered array arranged in ascending order is transformed into a highly balanced binary search tree.

In this question, a height balanced binary tree means that the absolute value of the height difference between the left and right subtrees of each node of a binary tree does not exceed 1.

Example:

Given an ordered array: [-10, -3,0,5,9],

A possible answer is: [0, -3,9, -10, null, 5], which can represent the following highly balanced binary search tree:

      0
     / \
   -3   9
   /   /
 -10  5

thinking

First, according to the title description, this title provides an ascending array. We all know that the binary search tree is characterized by ordered traversal. Therefore, we can treat this problem as restoring the result of traversal in binary search tree. At the same time, the title gives a condition that the height difference does not exceed 1, that is, the left and right sides are balanced. In this way, the binary search can be used. The mid index is actually the location of the corresponding root node. The left side of the mid is the left subtree of the root node, and the opposite is the right subtree. Recursion in turn can solve this problem.

code

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        if (nums == null || nums.length == 0) return null;

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

    TreeNode build(int[] nums, int left, int right) {
        if (left > right) return null;

        int mid = (right - left) / 2 + left;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = build(nums, left, mid - 1);
        root.right = build(nums, mid + 1, right);

        return root;
    }
}

109. ordered linked list transformation binary search tree

Title Description

Given a single linked list, the elements in it are sorted in ascending order, and it is transformed into a highly balanced binary search tree.

In this question, a height balanced binary tree means that the absolute value of the height difference between the left and right subtrees of each node of a binary tree does not exceed 1.

Example:

Given ordered linked list: [-10, -3, 0, 5, 9],

A possible answer is: [0, -3, 9, -10, null, 5], which can represent the following highly balanced binary search tree:


      0
     / \
   -3   9
   /   /
 -10  5
 

thinking

This topic is basically the same as 108. The difference is that this topic is to convert the linked list into a tree structure. The method of calculating intermediate nodes in linked lists is not as simple as that of arrays. Linked lists rely on fast and slow pointers

slow = node;
fast = node;
while (fast.next != boarder && != fast.next.next != null) {
    fast = fast.next.next;
    slow = slow.next;
}

return slow;

As long as we know how to calculate the intermediate nodes of the linked list, we can continue to use the binary structure to build the tree structure.

code

class Solution {
    public TreeNode sortedListToBST(ListNode head) {
        if (head == null) return null;

        return build(head, null);
    }

    TreeNode build(ListNode left, ListNode right) {
        if (left == right) return null;
        ListNode mid = getMid(left, right);
        
        TreeNode root = new TreeNode(mid.val);
        root.left = build(left, mid);
        root.right = build(mid.next, right);

        return root;
    }

    ListNode getMid(ListNode left, ListNode right){
        ListNode slow = left;
        ListNode fast = left;
        
        while (fast.next != right && fast.next.next != right) {
            slow = slow.next;
            fast = fast.next.next;
        }

        return slow;
    }

114. expand binary tree into linked list

Title Description

Given a binary tree, expand it into a single linked list in place.

1
   / \
  2   5
 / \   \
3   4   6
Expand it to:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

thinking

The expansion sequence is actually the sequence of preorder traversal. Therefore, we can first perform preorder traversal of the linked list, and the traversal results are stored in the list.

When expanding, construct the relationship in order, and set the left node to null.

The parent node of the current node is the right subtree of the previous node

code

class Solution {
    
    List<TreeNode> list = new ArrayList<>();
    public void flatten(TreeNode root) {
        if (root == null) return ;
        
        pre(root);
        TreeNode pre = null;
        TreeNode cur = null;
        for (int i = 1; i < list.size(); i++) {
            pre = list.get(i - 1);
            cur = list.get(i);

            pre.left = null;
            pre.right = cur;
        }
    }

    void pre(TreeNode root) {
        if (root != null) {
            list.add(root);
            
            pre(root.left);
            pre(root.right);
        }
    }
}