LeetCode 1245 - Tree Diameter


https://leetcode.jp/problemdetail.php?id=1245
Given an undirected tree, return its diameter: the number of edges in a longest path in that tree.
The tree is given as an array of edges where edges[i] = [u, v] is a bidirectional edge between nodes u and v.  Each node has labels in the set {0, 1, ..., edges.length}.

Example 1:
Input: edges = [[0,1],[0,2]]
Output: 2
Explanation: 
A longest path of the tree is the path 1 - 0 - 2.
Example 2:
Input: edges = [[0,1],[1,2],[2,3],[1,4],[4,5]]
Output: 4
Explanation: 
A longest path of the tree is the path 3 - 2 - 1 - 4 - 5.

Constraints:


  • 0 <= edges.length < 10^4
  • edges[i][0] != edges[i][1]
  • 0 <= edges[i][j] <= edges.length
  • The given edges form an undirected tree.
https://www.acwing.com/solution/LeetCode/content/5794/
(深度优先遍历) O(n)
  1. 根据边集数组建邻接表表示树。
  2. 我们采用深度优先遍历的方式从 0 号点开始遍历。递归函数返回当前结点的最长路径。
  3. 在遍历当前点的子结点的过程中,我们找到他们递归函数返回值加 1 的最大值次大值
  4. 更新答案最大值加次大值,然后返回最大值。

时间复杂度

  • 每个结点仅遍历一次,故时间复杂度为 O(n)

空间复杂度

  • 需要额外 O(n) 的空间存储邻接表。
    int ans;
    vector<vector<int>> graph;

    int dfs(int x, int fa) {
        int max1 = 0, max2 = 0;
        for (int v : graph[x])
            if (v != fa) {
                int t = dfs(v, x) + 1;
                if (max1 < t) {
                    max2 = max1;
                    max1 = t;
                } else if (max2 < t) {
                    max2 = t;
                }
            }

        ans = max(ans, (max1 + max2));
        return max1;
    }

    int treeDiameter(vector<vector<int>>& edges) {
        int n = edges.size() + 1;
        graph.resize(n);
        for (const auto &e : edges) {
            graph[e[0]].push_back(e[1]);
            graph[e[1]].push_back(e[0]);
        }
        ans = 0;

        dfs(0, -1);

        return ans;
    }
解题思路:本题是一道图上做有记忆的dfs搜索的题目,是无向图,给定的输入是图的各个边,题目中给出一个关键信息(Each node has labels in the set {0, 1, ..., edges.length})可知图中没有环,如果是有环的图这个题是无解的。最好的证明方法就是反正法,如果有环的话标号最大的节点必然小于边的数量,例如[0, 1], [1, 2], [0, 2], 三个节点且三条边,但编号最大的节点小于边的数量。

作为一个无向不联通图,节点主要分为两种类型,一种可以称为叶节点(这个并非是官方的名字,只是我自己叫着方便),即只有一个边与它连接,除来叶节点之外的节点则至少有两个边相连。

题目要求找出最长的一个path依次来定义这个tree的直径,很显然直径的选择是从一个叶节点到另外一个叶节点,在构建完图之后找到所有的叶节点,开始进行dfs的遍历,找出其中最长的一条路径来定义树的直径。

这个题目的模型与 568. Maximum Vacation Days 最大的不同是在计算过的值的记忆部分。

在568中每个节点的进与出的部分很清晰的分离,因此只要计算过一次,下一次递归不团从哪个节点进,都返回同样的答案。

本题则需要根据不同的输入返回不同的结果,所以memo的数据结构也不一样,对于每一个节点,需要用一个map来对应该节点到下一个节点的答案。这个地方需要使用map,而不是vector,因为需要使用到下一个节点的序号来索引。如果选择vector,无法将序号转换成下表。

时间复杂度:对于每一个节点而言,图需要计算各个出的值,复杂度为 O(e)

空间复杂度:存储每个节点到每一个方向的值 O(e)

class Solution {
public:
    int recursive(vector<vector<int>>& graph, vector<map<int, int>>& memo, vector<bool>& visited, int cur){
        int len = 0;
        for(int i = 0; i < graph[cur].size(); ++i){
            int next = graph[cur][i];
            if(!visited[next]){
                visited[next] = true;
                if(memo[cur][next] == 0){
                    memo[cur][next] = recursive(graph, memo, visited, next) + 1;
                }
                len = max(len, memo[cur][next]); 
            }
        }
        return len;
    }
    
    int treeDiameter(vector<vector<int>>& edges) {
        const int nodeCnt = edges.size() + 1;
        vector<vector<int>> graph(nodeCnt, vector<int>());
        vector<map<int, int>> memo(nodeCnt, map<int, int>());  // map<int, int>: first: the index of next node, second: the value if jump to the node
        for(auto edge : edges){
            graph[edge[0]].push_back(edge[1]);
            graph[edge[1]].push_back(edge[0]);
            memo[edge[0]][edge[1]] = 0;
            memo[edge[1]][edge[0]] = 0;
        }
        int ans = 0;
        for(int i = 0; i < graph.size(); ++i){
            if(graph[i].size() == 1){
                vector<bool> visited(nodeCnt, false);
                visited[i] = true;
                ans = max(ans, recursive(graph, memo, visited, i));
            }
        }
        return ans;
    }
};
Method 1: depth – first:
class Solution:
    def treeDiameter(self, edges: List[List[int]]) -> int:
        adjacency = collections.defaultdict(set)
        for i,j in edges:
            adjacency[i].add(j)
            adjacency[j].add(i)
        memo = {}
        def dfs(i,j):
            if (i,j) in memo:
                return memo[i,j]
            longest = 0
            for k in adjacency[j]:
                if k == i:continue
                longest = max(longest,dfs(j,k))
            memo[(i,j)] = longest + 1
            return memo[(i,j)]
        for i,j in edges:
            dfs(i,j)
            dfs(j,i)
        return max(memo[(i,j)]+memo[(j,i)]-1 for i,j in edges)
Method 2: Breadth – first
class Solution:
    def treeDiameter(self, edges: List[List[int]]) -> int:
        adjacency = collections.defaultdict(set)
        for i,j in edges:
            adjacency[i].add(j)
            adjacency[j].add(i)
        def bfs(node):
            queue = collections.deque()
            queue.append((node,0))
            memo = {node}
            while queue:
                n,long = queue.popleft()
                for nei in adjacency[n]:
                    if nei not in memo:
                        memo.add(nei)
                        queue.append((nei,long+1))
            return n,long
        
        far,long = bfs(0)
        far2,longest = bfs(far)
        return longest


Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts