Постановка на проблема

Като се има предвид root на двоично дърво, върнете обхождането на ниво отдолу нагоре на стойностите на неговите възли. (т.е. отляво надясно, ниво по ниво от листа до корена).

Изявлението на проблема е взето от: https://leetcode.com/problems/binary-tree-level-order-traversal-ii/

Пример 1:

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

Пример 2:

Input: root = [1]
Output: [[1]]

Пример 3:

Input: root = []
Output: []

Ограничения:

- The number of nodes in the tree is in the range [0, 2000].
- -1000 <= Node.val <= 1000

Обяснение

Изложението на проблема е подобно на старата ни публикация в блога „LeetCode Binary Tree Level Order Traversal“. Вместо да отпечатваме нивата ред по ред отгоре надолу, трябва да ги отпечатаме в обратен ред.

Рекурсивна функция

Можем да модифицираме рекурсивното решение на LeetCode Binary Tree Level Order Traversal, за да отпечатаме нивото на дървото отдолу нагоре.

C++ фрагмент от решението ще бъде както по-долу.

void reverseLevelOrder(node* root) {
    int h = height(root);
    int i;

    for(i = h; i >= 1; i--)
        printGivenLevel(root, i);
}

void printGivenLevel(node* root, int level) {
    if (root == NULL)
        return;

    if (level == 1)
        cout << root->data << ' ';
    else if (level > 1)
    {
        printGivenLevel(root->left, level - 1);
        printGivenLevel(root->right, level - 1);
    }
}

int height(node* node) {
    if (node == NULL)
        return 0;
    else
    {
        int lheight = height(node->left);
        int rheight = height(node->right);

        if (lheight > rheight)
            return(lheight + 1);
        else return(rheight + 1);
    }
}

Времевата сложност на горния подход е O(n^2), а пространствената сложност е O(n).

Опашки: итеративно решение

Можем да намалим времевата сложност до O(n), като използваме итеративен подход с опашки.

Нека проверим алгоритъма.

- initialize 2D array as vector vector<vector<int>> result
- initialize size and i

- return result if root == null

- initialize queue<TreeNode*> q
  - push root to queue : q.push(root)

- initialize TreeNode* node for iterating on the tree

- loop while( !q.empty() ) // queue is not empty
  - initialize vector<int> tmp
  - set size = q.size()

  - loop for i = 0; i < size; i++
    - set node = q.front()

    - if node->left
      - push in queue: q.push(node->left)

    - if node->right
      - push in queue: q.push(node->right)

    - remove the front node: q.pop()
    - push node->val to tmp. tmp.push_back(node->val)

  - push the tmp to result: result.push_back(tmp)
- loop while end

- reverse result

- return result

Времевата сложност на горния подход е O(n), а пространствената сложност е O(n).

Нека проверим нашия алгоритъм в C++, Golang и Javascript.

C++ решение

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> result;
        int size, i;

        if(root == NULL)
            return result;

        queue<TreeNode*> q;
        q.push(root);

        TreeNode* node;

        while(!q.empty()){
            vector<int> tmp;
            size = q.size();

            for(i = 0; i < size; i++){
                node = q.front();
                if(node->left)
                    q.push(node->left);

                if(node->right)
                    q.push(node->right);

                q.pop();
                tmp.push_back(node->val);
            }

            result.push_back(tmp);
        }

        reverse(result.begin(), result.end());

        return result;
    }
};

Разтвор на Golang

func levelOrderBottom(root *TreeNode) [][]int {
    result := [][]int{}

    queue := []*TreeNode{root}

    for len(queue) != 0 {
        tmp := []int{}
        size := len(queue)

        for i := 0; i < size; i++ {
            if queue[0] != nil {
                tmp = append(tmp, queue[0].Val)
                queue = append(queue, queue[0].Left)
                queue = append(queue, queue[0].Right)
            }

            queue = queue[1:]
        }

        result = append(result, tmp)
    }

    result = reverse(result)

    return result[1:]
}

func reverse(input [][]int) [][]int {
    var output [][]int

    for i := len(input) - 1; i >= 0; i-- {
        output = append(output, input[i])
    }

    return output
}

Javascript решение

var levelOrderBottom = function(root) {
    let result = [];
    let queue = [];

    if(root)
        queue.push(root);

    while(queue.length > 0) {
        tmp = [];
        let len = queue.length;

        for (let i = 0; i< len; i++) {
            let node = queue.shift();
            tmp.push(node.val);

            if(node.left) {
                queue.push(node.left);
            }

            if(node.right) {
                queue.push(node.right);
            }
        }

        result.push(tmp);
    }

    return result.reverse();
};

Нека изпробваме нашия алгоритъм, за да видим как работи решението.

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

Step 1: vector<vector<int>> result;
        int size, i;

Step 2: root == null
        [3, 9..] == null
        false

Step 3: queue<TreeNode*> q;
        q.push(root);

        q = [3]

Step 4: loop !q.empty()
        q = [3]
        q.empty() = false
        !false = true

        vector<int> tmp
        size = q.size()
             = 1

        for(i = 0; i < 1; i++)
          - 0 < 1
          - true

          node = q.front()
          node = 3

          if node->left
            - node->left = 9
            - q.push(node->left)
            - q = [3, 9]

          if node->right
            - node->right = 20
            - q.push(node->right)
            - q = [3, 9, 20]


          q.pop()
          q = [9, 20]

          tmp.push_back(node->val)
          tmp.push_back(3)

          i++
          i = 1

        for(i < 1)
        1 < 1
        false

        result.push_back(tmp)
        result = [[3]]

Step 5: loop !q.empty()
        q = [9, 20]
        q.empty() = false
        !false = true

        vector<int> tmp
        size = q.size()
             = 2

        for(i = 0; i < 2; i++)
          - 0 < 2
          - true

          node = q.front()
          node = 9

          if node->left
            - node->left = nil
            - false

          if node->right
            - node->right = nil
            - false

          q.pop()
          q = [20]

          tmp.push_back(node->val)
          tmp.push_back(9)

          i++
          i = 1

        for(i < 2)
          - 1 < 2
          - true

          node = q.front()
          node = 20

          if node->left
            - node->left = 15
            - q.push(node->left)
            - q = [20, 15]

          if node->right
            - node->left = 7
            - q.push(node->right)
            - q = [20, 15, 7]

          q.pop()
          q = [15, 7]

          tmp.push_back(node->val)
          tmp.push_back(20)
          tmp = [9, 20]

          i++
          i = 2

        for(i < 2)
          - 2 < 2
          - false

        result.push_back(tmp)
        result = [[3], [9, 20]]

Step 6: loop !q.empty()
        q = [15, 7]
        q.empty() = false
        !false = true

        vector<int> tmp
        size = q.size()
             = 2

        for(i = 0; i < 2; i++)
          - 0 < 2
          - true

          node = q.front()
          node = 15

          if node->left
            - node->left = nil
            - false

          if node->right
            - node->right = nil
            - false

          q.pop()
          q = [7]

          tmp.push_back(node->val)
          tmp.push_back(15)

          i++
          i = 1

        for(i < 2)
          - 1 < 2
          - true

          node = q.front()
          node = 7

          if node->left
            - node->left = nil
            - false

          if node->right
            - node->right = nil
            - false

          q.pop()
          q = []

          tmp.push_back(node->val)
          tmp.push_back(7)
          tmp = [15, 7]

          i++
          i = 2

        for(i < 2)
          - 2 < 2
          - false

        result.push_back(tmp)
        result = [[3], [9, 20], [15, 7]]

Step 7: loop !q.empty()
        q = []
        q.empty() = true
        !true = false

Step 8: reverse(result.begin(), result.end())

Step 9: return result

So we return the result as [[15, 7], [9, 20], [3]].