[LeetCode] Closest Leaf in a Binary Tree 二叉樹中最近的葉結點


 

Given a binary tree where every node has a unique value, and a target key k, find the value of the nearest leaf node to target k in the tree.

Here, nearest to a leaf means the least number of edges travelled on the binary tree to reach any leaf of the tree. Also, a node is called a leaf if it has no children.

In the following examples, the input tree is represented in flattened form row by row. The actual root tree given will be a TreeNode object.

Example 1:

Input:
root = [1, 3, 2], k = 1
Diagram of binary tree:
          1
         / \
        3   2

Output: 2 (or 3)

Explanation: Either 2 or 3 is the nearest leaf node to the target of 1.

 

Example 2:

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

Explanation: The nearest leaf node is the root node itself.

 

Example 3:

Input:
root = [1,2,3,4,null,null,null,5,null,6], k = 2
Diagram of binary tree:
             1
            / \
           2   3
          /
         4
        /
       5
      /
     6

Output: 3
Explanation: The leaf node with value 3 (and not the leaf node with value 6) is nearest to the node with value 2.

 

Note:

  1. root represents a binary tree with at least 1 node and at most 1000 nodes.
  2. Every node has a unique node.val in range [1, 1000].
  3. There exists some node in the given binary tree for which node.val == k.

 

這道題讓我們找二叉樹中最近的葉結點,葉結點就是最底端沒有子結點的那個。我們觀察題目中的例子3,發現結點2的最近葉結點是其右邊的那個結點3,那么傳統的二叉樹的遍歷只能去找其子結點中的葉結點,像這種同一層水平的結點該怎么弄呢?我們知道樹的本質就是一種無向圖,但是樹只提供了父結點到子結點的連接,反過來就不行了,所以只要我們建立了反向連接,就可以用BFS來找最近的葉結點了。明白了這一點后,我們就先來做反向連接吧,用一個哈希map,建立子結點與其父結點之間的映射,其實我們不用做完所有的反向連接,而是做到要求的結點k就行了,因為結點k的子結點可以直接訪問,不需要再反過來查找。我們用DFS來遍歷結點,並做反向連接,直到遇到結點k時,將其返回。此時我們得到了結點k,並且做好了結點k上面所有結點的反向連接,那么就可以用BFS來找最近的葉結點了,將結點k加入隊列queue和已訪問集合visited中,然后開始循環,每次取出隊首元素,如果是葉結點,說明已經找到了最近葉結點,直接返回;如果左子結點存在,並且不在visited集合中,那么先將其加入集合,然后再加入隊列,同理,如果右子結點存在,並且不在visited集合中,那么先將其加入集合,然后再加入隊列;再來看其父結點,如果不在visited集合中,那么先將其加入集合,然后再加入隊列。因為題目中說了一定會有結點k,所以在循環內部就可以直接返回了,不會有退出循環的可能,但是為表尊重,我們最后還是加上return -1吧, 參見代碼如下:

 

解法一:

class Solution {
public:
    int findClosestLeaf(TreeNode* root, int k) {
        unordered_map<TreeNode*, TreeNode*> back;
        TreeNode *kNode = find(root, k, back);
        queue<TreeNode*> q{{kNode}};
        unordered_set<TreeNode*> visited{{kNode}};
        while (!q.empty()) {
            TreeNode *t = q.front(); q.pop();
            if (!t->left && !t->right) return t->val;
            if (t->left && !visited.count(t->left)) {
                visited.insert(t->left);
                q.push(t->left);
            }
            if (t->right && !visited.count(t->right)) {
                visited.insert(t->right);
                q.push(t->right);
            }
            if (back.count(t) && !visited.count(back[t])) {
                visited.insert(back[t]);
                q.push(back[t]);
            }
        }
        return -1;
    }
    TreeNode* find(TreeNode* node, int k, unordered_map<TreeNode*, TreeNode*>& back) {
        if (node->val == k) return node;
        if (node->left) {
            back[node->left] = node;
            TreeNode *left = find(node->left, k, back);
            if (left) return left;
        }
        if (node->right) {
            back[node->right] = node;
            TreeNode *right = find(node->right, k, back);
            if (right) return right;
        }
        return NULL;
    }
};

 

下面這種解法也挺巧妙的,雖然沒有像上面的解法那樣建立所有父結點的反向連接,但是這種解法直接提前算出來了所有父結點到結點k的距離,就比如說例子3中,結點k的父結點只有一個,即為結點1,那么算出其和結點k的距離為1,即建立結點1和距離1之間的映射,另外建立結點k和0之間的映射,這樣便於從結點k開始像葉結點統計距離。接下來,我們維護一個最小值mn,表示結點k到葉結點的最小距離,還有結果res,指向那個最小距離的葉結點。下面就開始再次遍歷二叉樹了,如果當前結點為空, 直接返回。否則先在哈希map中看當前結點是否有映射值,有的話就取出來(如果有,則說明當前結點可能k或者其父結點),如果當前結點是葉結點了,那么我們要用當前距離cur和最小距離mn比較,如果cur更小的話,就將mn更新為cur,將結果res更新為當前結點。否則就對其左右子結點調用遞歸函數,注意cur要加1,參見代碼如下:

 

解法二:

class Solution {
public:
    int findClosestLeaf(TreeNode* root, int k) {
        int res = -1, mn = INT_MAX;
        unordered_map<int, int> m;
        m[k] = 0;
        find(root, k, m);
        helper(root, -1, m, mn, res);
        return res;
    }
    int find(TreeNode* node, int k, unordered_map<int, int>& m) {
        if (!node) return -1;
        if (node->val == k) return 1;
        int r = find(node->left, k, m);
        if (r != -1) {
            m[node->val] = r; 
            return r + 1;
        }
        r = find(node->right, k, m);
        if (r != -1) {
            m[node->val] = r;
            return r + 1;
        }
        return -1;
    }
    void helper(TreeNode* node, int cur, unordered_map<int, int>& m, int& mn, int& res) {
        if (!node) return;
        if (m.count(node->val)) cur = m[node->val];
        if (!node->left && !node->right) {
            if (mn > cur) {
                mn = cur; 
                res = node->val;
            }
        }
        helper(node->left, cur + 1, m, mn, res);
        helper(node->right, cur + 1, m, mn, res);
    }
};

 

參考資料:

https://leetcode.com/problems/closest-leaf-in-a-binary-tree/

https://leetcode.com/problems/closest-leaf-in-a-binary-tree/discuss/109960/java-dfs-bfs-27ms

https://leetcode.com/problems/closest-leaf-in-a-binary-tree/discuss/109963/java-short-solution28-ms-solution

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM