[LeetCode] Longest Univalue Path 最長相同值路徑


 

Given a binary tree, find the length of the longest path where each node in the path has the same value. This path may or may not pass through the root.

Note: The length of path between two nodes is represented by the number of edges between them.

Example 1:

Input:

              5
             / \
            4   5
           / \   \
          1   1   5

Output:

2

Example 2:

Input:

              1
             / \
            4   5
           / \   \
          4   4   5

Output:

2

Note: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000.

 

這道題讓我們求最長的相同值路徑,跟之前那道 Count Univalue Subtrees 十分的類似,解法也很類似。對於這種樹的路徑問題,遞歸是不二之選。在遞歸函數中,我們首先對其左右子結點調用遞歸函數,得到其左右子樹的最大相同值路徑長度,下面就要來看當前結點和其左右子結點之間的關系了,如果其左子結點存在且和當前節點值相同,則left自增1,否則left重置0;同理,如果其右子結點存在且和當前節點值相同,則right自增1,否則right重置0。然后用left+right來更新結果res。而調用當前節點值的函數只能返回left和right中的較大值,因為如果還要跟父節點組path,就只能在左右子節點中選一條path,當然選值大的那個了,什么意思呢,舉個例子來說吧,比如下面的這棵二叉樹:

      1
     / \
    4   5
   / \   \
  4   4   5
 /
4

若此時的node是只有兩個結點的第二層的那個結點4,那么分別對其左右子結點調用遞歸,會得到 left = 1, right = 0,因為此時要跟結點4組成path,所以肯定挑左子結點(有兩個4的那條邊),那你會問為啥不能連上右子結點的那個4,這整條長度為3的path(left+right,此時的left和right已經分別自增1了,left=2,right=1)其實我們已經用來更新過結果res了。需要注意的是我們的遞歸函數helper返回值的意義,並不是經過某個結點的最長路徑的長度,最長路徑長度保存在了結果res中,不是返回值,返回的是以該結點為終點的最長路徑長度,這樣回溯的時候,我們還可以繼續連上其父結點,比如若根結點也是4的話,那么回溯到根結點的時候,路徑長度又可以增加了,參見代碼如下:

 

解法一:

class Solution {
public:
    int longestUnivaluePath(TreeNode* root) {
        int res = 0;
        helper(root, res);
        return res;
    }
    int helper(TreeNode* node, int& res) {
        if (!node) return 0;
        int left = helper(node->left, res);
        int right = helper(node->right, res);
        left = (node->left && node->val == node->left->val) ? left + 1 : 0;
        right = (node->right && node->val == node->right->val) ? right + 1 : 0;
        res = max(res, left + right);
        return max(left, right);
    }
};

 

下面這種解法跟上面的方法很類似,區別在於遞歸函數中多了一個參數,parent保存的是父結點值,其實仔細比較下兩種解法,發現就是加1的地方略有不同,那么這里helper的返回值意義就發生了變化,這里的返回值表示的是以當前結點的父結點為路徑終點的最大相同值路徑長度,這樣我們遞歸出來的left和right就不用再加1,直接可以求和並更新結果res了,由於當前結點的父結點值知道,那么我們和父結點值比較一下,如果相同,返回left和right中較大值並再加1,如果不同,則返回0,這是因為之前說的必須要以父結點為路徑終點,那么既然父結點的值不同,所以長度肯定是0了,參見代碼如下:

 

解法二:

class Solution {
public:
    int longestUnivaluePath(TreeNode* root) {
        int res = 0;
        if (root) helper(root, root->val, res);
        return res;
    }
    int helper(TreeNode* node, int parent, int& res) {
        if (!node) return 0;
        int left = helper(node->left, node->val, res);
        int right = helper(node->right, node->val, res);
        res = max(res, left + right);
        if (node->val == parent) return max(left, right) + 1;
        return 0;
    }
};

 

下面這種解法使用了兩個遞歸函數,使得寫法更加簡潔了,首先還是先判斷root是否為空,是的話返回0。然后對左右子節點分別調用當前函數,取其中較大值保存到變量sub中,表示左右子樹中最長的相同值路徑,然后就是要跟當前樹的最長相同值路徑比較,計算方法是對左右子結點調用一個helper函數,並把當前結點值傳進去,把返回值加起來和sub比較,取較大值返回。順便提一下,這里的helper函數的返回值的意義跟解法二中的是一樣的。在helper函數里,若當前結點為空,或者當前節點值不等於父結點值的話,返回0。否則結返回對左右子結點分別調用helper遞歸函數中的較大值加1,我們發現這種寫法跟求樹的最大深度很像,參見代碼如下:

 

解法三:

class Solution {
public:
    int longestUnivaluePath(TreeNode* root) {
        if (!root) return 0;
        int sub = max(longestUnivaluePath(root->left), longestUnivaluePath(root->right));
        return max(sub, helper(root->left, root->val) + helper(root->right, root->val));
    }
    int helper(TreeNode* node, int parent) {
        if (!node || node->val != parent) return 0;
        return 1 + max(helper(node->left, node->val), helper(node->right, node->val));
    }
};

 

類似題目:

Binary Tree Maximum Path Sum

Count Univalue Subtrees

Path Sum III 

 

參考資料:

https://leetcode.com/problems/longest-univalue-path/

https://leetcode.com/problems/longest-univalue-path/discuss/108136/JavaC%2B%2B-Clean-Code 

https://leetcode.com/problems/longest-univalue-path/discuss/108175/java-solution-with-global-variable

https://leetcode.com/problems/longest-univalue-path/discuss/108146/Concise-DFS-solution-with-no-global-variables

 

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


免責聲明!

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



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