Skip to content

Commit b76ad4e

Browse files
authored
Create README.md
1 parent 08cd626 commit b76ad4e

File tree

1 file changed

+305
-0
lines changed
  • 17 - Binary Tree Data Structure Problems/29 - Maximum Sum of Non-adjacent Nodes

1 file changed

+305
-0
lines changed
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
<h1 align='center'>Maximum - Sum of - Non-adjacent - Nodes</h1>
2+
3+
## Problem Statement
4+
5+
**Problem URL :** [Maximum Sum of Non-adjacent Nodes](https://www.geeksforgeeks.org/problems/maximum-sum-of-non-adjacent-nodes/1)
6+
7+
![image](https://github.com/user-attachments/assets/e498815b-a36e-4f91-b5cf-8db2347e0b45)
8+
![image](https://github.com/user-attachments/assets/e581af15-1ea6-454f-a871-a4f9c1c0b56b)
9+
10+
## Problem Explanation
11+
12+
### Problem Description
13+
The task is to find the maximum sum of non-adjacent nodes in a binary tree. Nodes are considered non-adjacent if they are not direct children of each other.
14+
15+
### Constraints
16+
1. Each node in the tree contains an integer value.
17+
2. The tree can have both positive and negative values.
18+
3. The structure of the tree can vary; it may be balanced or skewed.
19+
4. The maximum number of nodes is not specified but is usually within reasonable limits for typical binary trees.
20+
21+
### Real-World Analogy
22+
Imagine a situation where each node represents a house, and the value of the node is the amount of money in each house. You can only rob houses that are not directly next to each other (i.e., no two adjacent houses can be robbed). The goal is to maximize the total amount of money stolen without alerting the police (which happens if you rob adjacent houses).
23+
24+
### Edge Cases
25+
1. An empty tree should return 0.
26+
2. A tree with only one node should return the value of that node.
27+
3. A tree with all negative values should still return the maximum (least negative) node value.
28+
29+
## Step 2: Approach
30+
31+
### High-Level Overview
32+
The problem can be solved using a recursive approach with dynamic programming principles, where we compute two values at each node:
33+
1. The maximum sum including the node itself.
34+
2. The maximum sum excluding the node.
35+
36+
The maximum sum at any node is then determined by taking the maximum of these two values.
37+
38+
### Step-by-Step Breakdown
39+
1. **Recursive Function**: Create a recursive function that returns a pair of integers for each node:
40+
- The first integer represents the maximum sum when including that node.
41+
- The second integer represents the maximum sum when excluding that node.
42+
2. **Base Case**: If the current node is NULL, return (0, 0) since there are no nodes to consider.
43+
3. **Recursive Case**: For each node:
44+
- Calculate the results from the left and right children recursively.
45+
- The result for the current node when included is its value plus the sums from the children when excluded.
46+
- The result for the current node when excluded is the maximum sums from both children, regardless of whether they are included or excluded.
47+
4. **Combine Results**: Return the calculated pair for the current node.
48+
49+
### Pseudocode
50+
```plaintext
51+
function solve(node):
52+
if node is NULL:
53+
return (0, 0)
54+
55+
left = solve(node.left)
56+
right = solve(node.right)
57+
58+
include_current = node.value + left.second + right.second
59+
exclude_current = max(left.first, left.second) + max(right.first, right.second)
60+
61+
return (include_current, exclude_current)
62+
63+
function getMaxSum(root):
64+
ans = solve(root)
65+
return max(ans.first, ans.second)
66+
```
67+
68+
## Problem Solution
69+
```cpp
70+
class Solution{
71+
public:
72+
pair<int, int> solve(Node* root){
73+
if(root == NULL) {
74+
pair<int, int> p = make_pair(0, 0);
75+
return p;
76+
};
77+
78+
79+
pair<int, int> left = solve(root -> left);
80+
pair<int, int> right = solve(root -> right);
81+
82+
pair<int, int> res;
83+
res.first = root -> data + left.second + right.second;
84+
res.second = max(left.first, left.second) + max(right.first, right.second);
85+
86+
87+
return res;
88+
89+
}
90+
//Function to return the maximum sum of non-adjacent nodes.
91+
int getMaxSum(Node *root)
92+
{
93+
pair<int, int> ans = solve(root);
94+
return max(ans.first, ans.second);
95+
96+
}
97+
};
98+
```
99+
100+
## Problem Solution Explanation
101+
102+
Let's go through the code line by line:
103+
104+
#### Class Definition
105+
```cpp
106+
class Solution {
107+
public:
108+
```
109+
- This line defines a class named `Solution`. All the methods inside this class will be related to solving the problem.
110+
111+
#### Recursive Function: `solve`
112+
```cpp
113+
pair<int, int> solve(Node* root) {
114+
```
115+
- This function takes a pointer to the root of a binary tree (`Node* root`) and returns a pair of integers (`pair<int, int>`). The pair consists of:
116+
- `first`: The maximum sum of non-adjacent nodes including the current node.
117+
- `second`: The maximum sum of non-adjacent nodes excluding the current node.
118+
119+
##### Base Case
120+
```cpp
121+
if (root == NULL) {
122+
pair<int, int> p = make_pair(0, 0);
123+
return p;
124+
}
125+
```
126+
- **Explanation**: If the current node (`root`) is `NULL`, it means we've reached the end of a branch in the tree.
127+
- We return a pair `(0, 0)`, indicating that there are no nodes to consider in this path.
128+
- **Example**: If we call `solve` on a leaf node's child (which is `NULL`), it returns `(0, 0)`.
129+
130+
##### Recursive Calls
131+
```cpp
132+
pair<int, int> left = solve(root->left);
133+
pair<int, int> right = solve(root->right);
134+
```
135+
- **Explanation**: We make two recursive calls to solve the left and right subtrees of the current node:
136+
- `left` will hold the result from the left child.
137+
- `right` will hold the result from the right child.
138+
- Each recursive call will return a pair containing the sums for its respective subtree.
139+
140+
**Example**:
141+
For a tree like:
142+
```
143+
10
144+
/ \
145+
1 2
146+
/ \ \
147+
3 4 5
148+
```
149+
- Calling `solve(10)` will call `solve(1)` and `solve(2)`.
150+
151+
##### Result Calculation
152+
```cpp
153+
pair<int, int> res;
154+
```
155+
- **Explanation**: We create a new pair `res` to store the results for the current node.
156+
157+
```cpp
158+
res.first = root->data + left.second + right.second;
159+
```
160+
- **Explanation**: This calculates the maximum sum when including the current node (`root`):
161+
- `root->data`: Value of the current node.
162+
- `left.second`: The maximum sum of non-adjacent nodes from the left child when it's excluded.
163+
- `right.second`: The maximum sum of non-adjacent nodes from the right child when it's excluded.
164+
- The logic here is that if we include the current node, we cannot include its immediate children, hence we add the `second` values from both children.
165+
166+
**Example**:
167+
If `root->data` is `10`, `left.second` is `4` (sum excluding node `1`), and `right.second` is `5` (sum excluding node `2`), then:
168+
- `res.first = 10 + 4 + 5 = 19`.
169+
170+
```cpp
171+
res.second = max(left.first, left.second) + max(right.first, right.second);
172+
```
173+
- **Explanation**: This calculates the maximum sum when excluding the current node:
174+
- `max(left.first, left.second)`: Choose the maximum sum from the left child, whether we include it or not.
175+
- `max(right.first, right.second)`: Choose the maximum sum from the right child, whether we include it or not.
176+
- The idea here is that if we exclude the current node, we can freely choose to include or exclude its children based on which gives a higher sum.
177+
178+
**Example**:
179+
Continuing from our previous example, if:
180+
- `left.first = 7` (including node `1`),
181+
- `left.second = 4` (excluding node `1`),
182+
- `right.first = 5` (including node `2`),
183+
- `right.second = 5` (excluding node `2`),
184+
Then:
185+
- `res.second = max(7, 4) + max(5, 5) = 7 + 5 = 12`.
186+
187+
##### Return Result
188+
```cpp
189+
return res;
190+
```
191+
- **Explanation**: This returns the computed pair `res` for the current subtree.
192+
- The function will eventually return results all the way back up to the root.
193+
194+
#### Main Function: `getMaxSum`
195+
```cpp
196+
int getMaxSum(Node *root) {
197+
```
198+
- This function is called to get the maximum sum of non-adjacent nodes in the entire binary tree.
199+
200+
```cpp
201+
pair<int, int> ans = solve(root);
202+
```
203+
- **Explanation**: Calls the `solve` function with the root node and stores the result in `ans`.
204+
205+
```cpp
206+
return max(ans.first, ans.second);
207+
```
208+
- **Explanation**: Returns the maximum of the two sums computed from `solve(root)`.
209+
- This gives the overall maximum sum of non-adjacent nodes in the tree.
210+
211+
### Example Execution Flow
212+
Let's trace the execution for the tree:
213+
```
214+
10
215+
/ \
216+
1 2
217+
/ \ \
218+
3 4 5
219+
```
220+
221+
1. **Start at the root (10)**:
222+
- Call `solve(10)`.
223+
2. **Move to the left child (1)**:
224+
- Call `solve(1)`.
225+
3. **Move to the left child (3)**:
226+
- Call `solve(3)`.
227+
- Both children of 3 are NULL, so it returns `(3, 0)`.
228+
4. **Return to (1)** and process the right child (4):
229+
- Call `solve(4)`.
230+
- Both children of 4 are NULL, so it returns `(4, 0)`.
231+
5. **Now for node (1)**:
232+
- `res.first = 1 + 0 + 0 = 1` (including 1)
233+
- `res.second = max(3, 0) + max(4, 0) = 3 + 4 = 7` (excluding 1)
234+
- Returns `(1, 7)` for node (1).
235+
6. **Return to the root (10)** and process the right child (2):
236+
- Call `solve(2)`.
237+
7. **Move to the right child (5)**:
238+
- Call `solve(5)`.
239+
- Both children of 5 are NULL, so it returns `(5, 0)`.
240+
8. **Now for node (2)**:
241+
- Left child is NULL, so `left = (0, 0)`.
242+
- `res.first = 2 + 0 + 0 = 2`.
243+
- `res.second = max(0, 0) + max(5, 0) = 0 + 5 = 5`.
244+
- Returns `(2, 5)` for node (2).
245+
9. **Finally for the root (10)**:
246+
- `res.first = 10 + 7 + 5 = 22`.
247+
- `res.second = max(1, 7) + max(2, 5) = 7 + 5 = 12`.
248+
- Returns `(22, 12)`.
249+
250+
The final answer from `getMaxSum(root)` is `max(22, 12)`, which is `22`.
251+
252+
Let's consider the following binary tree:
253+
```
254+
10
255+
/ \
256+
1 2
257+
/ \ \
258+
3 4 5
259+
```
260+
261+
### Example 1
262+
**Input**: The tree above.
263+
264+
- **Expected Output**: The maximum sum of non-adjacent nodes is `10 + 4 + 5 = 19`.
265+
266+
### Example 2
267+
**Input**: An empty tree.
268+
269+
- **Expected Output**: `0`, since there are no nodes.
270+
271+
### Example 3
272+
**Input**: A tree with all negative values.
273+
```
274+
-1
275+
/ \
276+
-2 -3
277+
/ \ \
278+
-4 -5 -6
279+
```
280+
281+
- **Expected Output**: The maximum (least negative) node value is `-1`.
282+
283+
### Example 4
284+
**Input**: A single-node tree.
285+
```
286+
7
287+
```
288+
289+
- **Expected Output**: `7`, as it's the only node.
290+
291+
### Explanation of Outputs
292+
- The maximum sum is calculated by selecting nodes that are non-adjacent while maximizing their total value. In each example, we carefully select which nodes to include based on their position in the tree.
293+
294+
## Step 5: Time and Space Complexity
295+
296+
### Time Complexity
297+
- **Recursive Calls**: Each node in the binary tree is visited once. Therefore, the time complexity is **O(N)**, where N is the number of nodes in the tree.
298+
299+
### Space Complexity
300+
- **Recursive Stack Space**: The space complexity due to the recursion stack can go up to **O(H)**, where H is the height of the tree. In the worst case (for example, a skewed tree), this can be **O(N)**. For balanced trees, it is **O(log N)**.
301+
302+
### Summary
303+
- The solution is efficient for typical binary trees, visiting each node once and storing results in pairs. It effectively handles various tree structures while maximizing the sum of non-adjacent nodes.
304+
305+
With this detailed breakdown, you should have a clear understanding of the problem, the approach taken, the code implementation, and the complexities involved. If you have any further questions or need clarifications, feel free to ask!

0 commit comments

Comments
 (0)