|
| 1 | +<h1 align='center'>Sum of Nodes - on The - Longest Path - from Root - to Leaf - Node</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Sum of Nodes on The Longest Path from Root to Leaf Node](https://www.geeksforgeeks.org/problems/sum-of-the-longest-bloodline-of-a-tree/1) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Problem Explanation |
| 11 | +Given a binary tree, the task is to find the largest sum of all nodes on a path from the root to a leaf node, where the path with the most nodes is chosen in case of a tie. A path is defined as any sequence from the root to a leaf node. If multiple paths have the same length, choose the path that has the maximum sum. |
| 12 | + |
| 13 | +**Example:** |
| 14 | +Consider the following binary tree: |
| 15 | + |
| 16 | +``` |
| 17 | + 10 |
| 18 | + / \ |
| 19 | + 20 30 |
| 20 | + / \ / |
| 21 | + 40 50 60 |
| 22 | +``` |
| 23 | + |
| 24 | +In this case: |
| 25 | +- The longest path from the root to a leaf node is either `10 -> 20 -> 50` or `10 -> 30 -> 60`. |
| 26 | +- The path with the maximum sum along the longest path is `10 -> 30 -> 60`, which has a sum of 100. |
| 27 | + |
| 28 | +**Constraints:** |
| 29 | +- If the tree is empty (root is `NULL`), the output should be `0`. |
| 30 | +- Handle edge cases like a single node tree or trees with only one child path. |
| 31 | + |
| 32 | +### Step 2: Approach |
| 33 | + |
| 34 | +**High-Level Overview:** |
| 35 | +The solution uses a recursive Depth First Search (DFS) traversal to explore each path from the root to every leaf node: |
| 36 | +1. Traverse through each node, keeping track of: |
| 37 | + - The cumulative sum of the path. |
| 38 | + - The length of the path from root to the current node. |
| 39 | +2. On reaching a leaf node, compare: |
| 40 | + - The length of this path with the longest path found so far. |
| 41 | + - If the path length is the same as the longest path, check if the current sum is greater than the maximum sum recorded. |
| 42 | + |
| 43 | +**Step-by-Step Breakdown:** |
| 44 | +1. **Define Base Condition**: When we reach a `NULL` node, it indicates a leaf node. We then compare the current path’s length and sum with the longest path and maximum sum recorded. |
| 45 | +2. **Recursive Traversal**: |
| 46 | + - Recursively call the function for the left child and the right child. |
| 47 | + - Update the sum and length parameters for each recursive call. |
| 48 | +3. **Update the Result**: |
| 49 | + - If the current path is longer, update `maxLen` and `maxSum`. |
| 50 | + - If the path length matches `maxLen`, update `maxSum` if the current sum is greater than `maxSum`. |
| 51 | + |
| 52 | +## Problem Solution |
| 53 | +```cpp |
| 54 | +class Solution |
| 55 | +{ |
| 56 | +public: |
| 57 | + void solve(Node* root, int sum, int &maxSum, int len, int &maxLen){ |
| 58 | + if(root == NULL){ |
| 59 | + if(len > maxLen){ |
| 60 | + maxLen = len; |
| 61 | + maxSum = sum; |
| 62 | + }else if(len == maxLen){ |
| 63 | + maxSum = max(sum, maxSum); |
| 64 | + } |
| 65 | + return; |
| 66 | + } |
| 67 | + |
| 68 | + sum = sum + root -> data; |
| 69 | + solve(root -> left, sum, maxSum, len+1, maxLen); |
| 70 | + solve(root -> right, sum, maxSum, len+1, maxLen); |
| 71 | + } |
| 72 | + |
| 73 | + int sumOfLongRootToLeafPath(Node *root) |
| 74 | + { |
| 75 | + |
| 76 | + int len = 0; |
| 77 | + int maxLen = 0; |
| 78 | + |
| 79 | + int sum = 0; |
| 80 | + int maxSum = INT_MIN; |
| 81 | + |
| 82 | + solve(root, sum, maxSum, len, maxLen); |
| 83 | + |
| 84 | + return maxSum; |
| 85 | + } |
| 86 | +}; |
| 87 | +``` |
| 88 | + |
| 89 | +## Problem Solution Explanation |
| 90 | +Let's go through each part of the code to understand how it works line-by-line, using examples for clarity. |
| 91 | + |
| 92 | +```cpp |
| 93 | +class Solution { |
| 94 | +public: |
| 95 | + // Helper function to find the sum of the longest root-to-leaf path |
| 96 | + void solve(Node* root, int sum, int &maxSum, int len, int &maxLen) { |
| 97 | +``` |
| 98 | +
|
| 99 | +### Line-by-Line Explanation |
| 100 | +
|
| 101 | +1. **Line:** `void solve(Node* root, int sum, int &maxSum, int len, int &maxLen)` |
| 102 | + - **Purpose:** This function recursively traverses the binary tree to find the path with the greatest length and sum from the root to a leaf node. |
| 103 | + - **Parameters:** |
| 104 | + - `Node* root`: Pointer to the current node. |
| 105 | + - `int sum`: Cumulative sum of the path from the root to the current node. |
| 106 | + - `int &maxSum`: Tracks the maximum sum found along the longest path so far (passed by reference to update the same variable across recursive calls). |
| 107 | + - `int len`: Current path length from the root to the current node. |
| 108 | + - `int &maxLen`: Tracks the maximum length of paths from the root to leaf nodes (also passed by reference). |
| 109 | +
|
| 110 | +### Example Tree |
| 111 | +Consider this example binary tree: |
| 112 | +``` |
| 113 | + 10 |
| 114 | + / \ |
| 115 | + 20 30 |
| 116 | + / \ / |
| 117 | + 40 50 60 |
| 118 | +``` |
| 119 | +
|
| 120 | +Starting at the root (node 10), the function will traverse the tree to find the longest path and the path with the highest sum. |
| 121 | +
|
| 122 | +
|
| 123 | +```cpp |
| 124 | + // Base condition: if current node is NULL |
| 125 | + if(root == NULL) { |
| 126 | +``` |
| 127 | + |
| 128 | +2. **Line:** `if(root == NULL)` |
| 129 | + - **Purpose:** Checks if the current node is `NULL`, indicating that we've reached a leaf node. At this point, we should evaluate the length and sum of the path that brought us here. |
| 130 | + |
| 131 | + |
| 132 | +```cpp |
| 133 | + // Check if the path length is greater than the longest path found |
| 134 | + if(len > maxLen) { |
| 135 | + maxLen = len; // Update the longest path length |
| 136 | + maxSum = sum; // Update the max sum for the longest path |
| 137 | + } else if(len == maxLen) { // If path length is the same, check sum |
| 138 | + maxSum = max(sum, maxSum); // Choose the maximum sum of paths |
| 139 | + } |
| 140 | + return; |
| 141 | + } |
| 142 | +``` |
| 143 | +
|
| 144 | +3. **Line:** `if(len > maxLen)` |
| 145 | + - **Purpose:** If the current path length (`len`) is greater than the previously recorded maximum path length (`maxLen`), we update `maxLen` to this longer length and set `maxSum` to the current path’s sum. |
| 146 | + |
| 147 | + **Example:** |
| 148 | + - When traversing the path `10 -> 20 -> 40`, if it’s the longest path found so far, update `maxLen` to 3 and `maxSum` to 70. |
| 149 | +
|
| 150 | +4. **Line:** `else if(len == maxLen)` |
| 151 | + - **Purpose:** If this path length is equal to the longest path length (`maxLen`), then we check if the current path’s sum is greater than `maxSum`. If it is, we update `maxSum` to the larger sum. |
| 152 | +
|
| 153 | + **Example:** |
| 154 | + - When visiting path `10 -> 20 -> 50` (sum 80), if `len == maxLen`, we compare 80 with the previous `maxSum`. Since 80 is higher, we set `maxSum` to 80. |
| 155 | +
|
| 156 | +
|
| 157 | +```cpp |
| 158 | + // Add the current node's data to the path sum |
| 159 | + sum = sum + root->data; |
| 160 | +``` |
| 161 | + |
| 162 | +5. **Line:** `sum = sum + root->data` |
| 163 | + - **Purpose:** Adds the current node’s value to `sum`, accumulating the total for the path so far. |
| 164 | + |
| 165 | + **Example:** |
| 166 | + - At node 10, `sum` becomes `10`. At node 20, `sum` becomes `30`, and so on. |
| 167 | + |
| 168 | +```cpp |
| 169 | + // Recursively call for the left and right child nodes |
| 170 | + solve(root->left, sum, maxSum, len + 1, maxLen); // Move to the left child |
| 171 | + solve(root->right, sum, maxSum, len + 1, maxLen); // Move to the right child |
| 172 | + } |
| 173 | +``` |
| 174 | +
|
| 175 | +6. **Line:** `solve(root->left, sum, maxSum, len + 1, maxLen)` |
| 176 | + - **Purpose:** Recursively moves to the left child of the current node, with updated `sum` and incremented `len`. This call continues until reaching a leaf node. |
| 177 | + |
| 178 | +7. **Line:** `solve(root->right, sum, maxSum, len + 1, maxLen)` |
| 179 | + - **Purpose:** Similarly, this recursive call explores the right child of the current node. |
| 180 | + |
| 181 | +**Example Execution:** Starting from `10`, the function will first go down the left subtree, visiting nodes `20` and `40`. Upon reaching `40` (a leaf node), it evaluates the path and then backtracks to try the right child of each node until it has explored all possible root-to-leaf paths. |
| 182 | +
|
| 183 | +
|
| 184 | +```cpp |
| 185 | + // Main function to initialize parameters and call helper function |
| 186 | + int sumOfLongRootToLeafPath(Node *root) { |
| 187 | +``` |
| 188 | + |
| 189 | +8. **Line:** `int sumOfLongRootToLeafPath(Node *root)` |
| 190 | + - **Purpose:** This is the main function that initializes the required variables (`len`, `maxLen`, `sum`, and `maxSum`) and calls the `solve` function. |
| 191 | + |
| 192 | + |
| 193 | +```cpp |
| 194 | + // Initialize parameters for maximum path length and sum |
| 195 | + int len = 0; |
| 196 | + int maxLen = 0; |
| 197 | + |
| 198 | + int sum = 0; |
| 199 | + int maxSum = INT_MIN; |
| 200 | + |
| 201 | + // Call helper function to find the maximum sum path |
| 202 | + solve(root, sum, maxSum, len, maxLen); |
| 203 | + |
| 204 | + // Return the maximum sum found for the longest path |
| 205 | + return maxSum; |
| 206 | + } |
| 207 | +}; |
| 208 | +``` |
| 209 | +
|
| 210 | +9. **Lines:** Initialization and Call |
| 211 | + - `len = 0` and `maxLen = 0`: Used to track the length of the current path and the maximum path length found so far. |
| 212 | + - `sum = 0` and `maxSum = INT_MIN`: Used to track the sum of the current path and the highest sum found among the longest paths. |
| 213 | +
|
| 214 | +10. **Line:** `solve(root, sum, maxSum, len, maxLen)` |
| 215 | + - Calls the `solve` helper function with the root of the tree to initiate the recursive exploration. |
| 216 | +
|
| 217 | +11. **Line:** `return maxSum` |
| 218 | + - Returns the `maxSum` value, which represents the sum of nodes along the longest root-to-leaf path. |
| 219 | +
|
| 220 | +
|
| 221 | +### Step 4: Output Examples |
| 222 | +
|
| 223 | +1. **Example 1:** |
| 224 | + - **Input**: Tree structure |
| 225 | + ``` |
| 226 | + 1 |
| 227 | + / \ |
| 228 | + 2 3 |
| 229 | + / \ / \ |
| 230 | + 4 5 6 7 |
| 231 | + ``` |
| 232 | + - **Output**: 11 (Path is `1 -> 3 -> 7`) |
| 233 | +
|
| 234 | +2. **Example 2:** |
| 235 | + - **Input**: Tree structure |
| 236 | + ``` |
| 237 | + 10 |
| 238 | + / \ |
| 239 | + -2 7 |
| 240 | + / \ / |
| 241 | + 8 -4 5 |
| 242 | + ``` |
| 243 | + - **Output**: 15 (Path is `10 -> 7 -> -2 -> 5`) |
| 244 | +
|
| 245 | +3. **Example 3 (Edge Case - Empty Tree)**: |
| 246 | + - **Input**: `root = NULL` |
| 247 | + - **Output**: `0` |
| 248 | +
|
| 249 | +--- |
| 250 | +
|
| 251 | +### Step 5: Time and Space Complexity |
| 252 | +
|
| 253 | +1. **Time Complexity**: \(O(N)\) |
| 254 | + - The function visits each node in the binary tree exactly once, where \(N\) is the number of nodes in the tree. Therefore, the time complexity is \(O(N)\). |
| 255 | +
|
| 256 | +2. **Space Complexity**: \(O(H)\) |
| 257 | + - The function’s recursive calls take up stack space. The maximum depth of the stack is the height \(H\) of the tree, giving a space complexity of \(O(H)\). In the worst case, \(H = N\) if the tree is skewed, but for a balanced tree, \(H = \log N\). |
| 258 | +
|
| 259 | +--- |
| 260 | +
|
| 261 | +### Additional Tips: |
| 262 | +- **Edge Cases**: Ensure to handle cases where the tree is empty or has only one node. |
| 263 | +- **Optimizations**: This approach is already efficient, but for very large trees, consider iterative solutions or tail-call optimization if supported. |
0 commit comments