[Warrior's notes] sword finger offer 32 Three questions, let you learn the depth and breadth first traversal and recursive iterative techniques of binary tree

Posted by lavender on Sun, 09 Jan 2022 00:51:29 +0100

Title one sword refers to Offer 32 - I. print binary tree from top to bottom

Source: LeetCode
Link: https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/

1. Description

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.

2. Examples

  • Example 1:
Given binary tree: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
 return:

[3,9,20,15,7]

Solution I breadth first traversal + auxiliary queue

Problem solving ideas

It's not difficult to think of the simplest way is to traverse the binary tree with the help of a queue.
1. If the root node is empty, an empty array is returned directly; otherwise, the queued root node;
2. Add the team head node value to the answer array;
3. The non empty child node of the incoming team head node will take the team head node out of the team.
4. Repeat 2 and 3 until the queue is empty.

code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> levelOrder(TreeNode* root) {
        vector<int> ans;//Store answers
        if(!root) return ans;//If the root node is empty, an empty answer array is returned
        queue<TreeNode*> q;//Auxiliary queue
        q.push(root);//Root node queue
        while(!q.empty()){//As long as the queue is not empty
            ans.push_back(q.front()->val);//Add the team head node value to the answer array
            //Non empty child node of queue header node
            if(q.front()->left) q.push(q.front()->left);
            if(q.front()->right) q.push(q.front()->right);
            q.pop();//Remove the team head node from the team
        }
        return ans;//Return answer
    }
};

Complexity analysis

Time complexity: O(m). M is the number of binary tree nodes. It takes O(m) time to traverse the whole binary tree.
Spatial complexity: O(m). Space consumption for storing answers and using auxiliary queues.

Solution 2 depth first search + auxiliary array

Problem solving ideas

In addition to the intuitive breadth first search, we can also use depth first search + auxiliary two-dimensional array to solve this problem.
Specifically, we perform a depth first search on the binary tree and maintain a level, which is initially 0. Every time you enter a layer of recursion, that is, when traversing the child node from the current node, the number of layers will be increased by one, then access the two-dimensional array through the number of layers as a subscript, add the node value to the one-dimensional array of the corresponding layer, and finally straighten the two-dimensional array by layers, which is the final answer.

code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> levelOrder(TreeNode* root) {
        vector<int> ans;//Store answers
        if(!root) return ans;//If the root node is empty, an empty array is returned
        vector<vector<int>> aid;//Auxiliary array
        dfs(root, 0, aid);//Depth first traversal
        for(auto a : aid) ans.insert(ans.end(), a.begin(), a.end());//Straighten the two-dimensional array by layer
        return ans; //Return answer
    }

    void dfs(TreeNode* root, int level, vector<vector<int>>& aid){
        if(!root) return;//If the node is empty, return
        if(aid.size()<=level){//If the layer array has not been created, create it
            vector<int> temp;
            aid.push_back(temp);
        }
        aid[level].push_back(root->val);//Add the node value to the corresponding layer array
        dfs(root->left, level+1, aid);//Traverse the left child node, and level+1
        dfs(root->right, level+1, aid);//Traverse the right child node, and level+1
    }
};

Complexity analysis

Time complexity: O(m). Recursion and the time consumption of straightening the two-dimensional array
Spatial complexity: O(m). Recursion and space consumption of auxiliary array and answer array.

Title 2: Sword finger Offer 32 - II Print binary tree II from top to bottom

Source: LeetCode
Link: https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/

1. Description

The binary tree is printed by layers from top to bottom, the nodes of the same layer are printed from left to right, and each layer is printed to one line.

2. Examples

  • Example 1:
Given binary tree: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
 Return its hierarchy traversal result:

[
  [3],
  [9,20],
  [15,7]
]

Solution I breadth first search + auxiliary queue

Problem solving ideas

Referring to topic 1, we can write the version of breadth first search + auxiliary queue.
However, a slight difference is that we need to choose the appropriate way to layer. Here, two additional variables count and size are used for hierarchical operation. For each layer, size is the size of the layer. Initially, it is 1, that is, the size of the queue when there is only the root node. For each node recorded, the count value is increased by one. When count is equal to size, it indicates that the current layer has been traversed. Then update the layer size and reset count to 0.
1. If the root node is empty, an empty array is returned directly; otherwise, the queued root node;
2. Add the team head node value to the answer array;
3. The non empty child node of the incoming team head node, and the team head node out of the team;
4. Add one to count. If count equals size, update size and reset count to 0;
5. Repeat the processes 2, 3 and 4 until the queue is empty.

code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ans;//Store answers
        if(!root) return ans;//If the root node is empty, an empty array is returned
        queue<TreeNode*> q;//Auxiliary queue
        q.push(root);//Queue root node
        int size = q.size(), count = 0;//Initialize size and count
        vector<int> temp;//Auxiliary array
        while(!q.empty()){//As long as the queue is not empty
            temp.push_back(q.front()->val);//Record the value of the queue head node
            //Non empty child node of queue header node
            if(q.front()->left) q.push(q.front()->left);
            if(q.front()->right) q.push(q.front()->right);
            q.pop();//Outgoing head node
            ++count;//count+1
            if(count == size){//If count==size, it means that the current layer has been recorded
                ans.push_back(temp);//Add temp to the answer array
                temp.clear();//Empty temp
                count = 0;//Reset count to 0
                size = q.size();//Update size
            }
        }
        return ans;//Return answer
    }
};

Complexity analysis

Time complexity: O(m). M is the number of binary tree nodes, and it takes O(m) time to traverse the whole binary tree.
Spatial complexity: O(m). Auxiliary queue, answer array, space consumption of auxiliary array.

Solution 2 depth first search + auxiliary array

Problem solving ideas

In addition to the intuitive breadth first search, we can also use depth first search + auxiliary two-dimensional array to solve this problem.
Specifically, we perform a depth first search on the binary tree and maintain a level, which is initially 0. Every time you enter a layer of recursion, that is, when traversing the child node from the current node, the number of layers will be increased by one, and then access the two-dimensional array through the number of layers as a subscript, and add the node value to the one-dimensional array of the corresponding layer. After traversing, it will be the final answer.

code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ans;//Store answers
        if(!root) return ans;//If the root node is empty, an empty array is returned
        dfs(root, 0, ans);//Depth first traversal
        return ans;//Return answer
    }

    void dfs(TreeNode* root, int level, vector<vector<int>>& aid){//Depth first traversal
        if(!root) return;//If the node is empty, return directly
        if(aid.size()<=level){//If the current layer array has not been created, create it
            vector<int> temp;
            aid.push_back(temp);
        }
        aid[level].push_back(root->val);//Save the current node value to the corresponding layer
        dfs(root->left, level+1, aid);//Traverse the left child, the number of layers plus one
        dfs(root->right, level+1, aid);//Traverse the right child, the number of layers plus one
    }
};

Complexity analysis

Time complexity: O(m). The time consumption of traversing the binary tree.
Spatial complexity: O(m). Stack space consumption for storing answers and recursion.

Title Three sword fingers Offer 32 - III. printing binary tree III from top to bottom

Source: LeetCode
Link: https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/

1. Description

Please implement a function to print the binary tree in zigzag order, 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.

2. Examples

  • Example 1:
Given binary tree: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
 Return its hierarchy traversal result:

[
  [3],
  [20,9],
  [15,7]
]

Solution I breadth first search + auxiliary queue

Problem solving ideas

Referring to topic 2, we can write the version of breadth first search + auxiliary queue.
We need to choose the right way to layer. Here, two additional variables count and size are used for hierarchical operation. For each layer, size is the size of the layer. Initially, it is 1, that is, the size of the queue when there is only the root node. For each node recorded, the count value is increased by one. When count is equal to size, it indicates that the current layer has been traversed. Then update the layer size and reset count to 0. However, the slight difference is that we need to process the result array after traversal, that is, flip the even layer array. The answer is after processing.
1. If the root node is empty, an empty array is returned directly; otherwise, the queued root node;
2. Add the team head node value to the answer array;
3. The non empty child node of the incoming team head node, and the team head node out of the team;
4. Add one to count. If count equals size, update size and reset count to 0;
5. Repeat processes 2, 3 and 4 until the queue is empty;
6. Flip the result array of even layers.

code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ans;//Store answers
        if(!root) return ans;//If the root node is empty, an empty array is returned
        queue<TreeNode*> q;//Auxiliary queue
        q.push(root);//Queue root node
        int size = q.size(), count = 0;//Initialize size and count
        vector<int> temp;//Auxiliary array
        while(!q.empty()){//As long as the queue is not empty
            temp.push_back(q.front()->val);//Record the value of the queue head node
            //Non empty child node of queue header node
            if(q.front()->left) q.push(q.front()->left);
            if(q.front()->right) q.push(q.front()->right);
            q.pop();//Outgoing head node
            ++count;//count+1
            if(count == size){//If count==size, it means that the current layer has been recorded
                ans.push_back(temp);//Add temp to the answer array
                temp.clear();//Empty temp
                count = 0;//Reset count to 0
                size = q.size();//Update size
            }
        }
        for(int i = 0; i < m; ++i) if(i%2!=0) reverse(ans[i].begin(), ans[i].end());//Flip even layers
        return ans;//Return answer
    }
};

Complexity analysis

Time complexity: O(m). M is the number of binary tree nodes. It takes O(m) time to traverse the whole binary tree and flip the even layer.
Spatial complexity: O(m). Auxiliary queue, answer array, space consumption of auxiliary array.

Solution 2 depth first traversal + auxiliary array

Problem solving ideas

The depth first traversal version is also provided here.

code

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ans;//Store answers
        if(!root) return ans;//If the root node is empty, an empty array is returned
        dfs(root, 0, ans);//Depth first traversal
        for(int i = 0; i < m; ++i) if(i%2!=0) reverse(ans[i].begin(), ans[i].end());//Flip even layers
        return ans;//Return answer
    }

    void dfs(TreeNode* root, int level, vector<vector<int>>& aid){//Depth first traversal
        if(!root) return;//If the node is empty, return directly
        if(aid.size()<=level){//If the current layer array has not been created, create it
            vector<int> temp;
            aid.push_back(temp);
        }
        aid[level].push_back(root->val);//Save the current node value to the corresponding layer
        dfs(root->left, level+1, aid);//Traverse the left child, the number of layers plus one
        dfs(root->right, level+1, aid);//Traverse the right child, the number of layers plus one
    }
};

Complexity analysis

Time complexity: O(m). The time consumption of traversing binary tree and flipping even layers.
Spatial complexity: O(m). Stack space consumption for storing answers and recursion.

Generally speaking, breadth first traversal is more intuitive, but the code is longer; The depth first traversal code is concise, but difficult to understand. Use more and practice more to master it.

More knowledge content sharing:
Blog Garden personal home page https://home.cnblogs.com/u/newCoderTheWarrior
Li Kou personal homepage https://leetcode-cn.com/profile/articles/

Topics: C++ Algorithm queue Binary tree array