Skip to content

Commit 780526a

Browse files
authored
Create README.md
1 parent 4b676e0 commit 780526a

File tree

1 file changed

+221
-0
lines changed
  • 14 - Linked List Data Structure Problems/01 - Singly Linked List Problems/24 - Merge K Sorted Linked Lists

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
<h1 align='center'>Merge - K Sorted - Linked - Lists</h1>
2+
3+
## Problem Statement
4+
5+
**Problem URL :** [Merge K Sorted Linked Lists](https://www.geeksforgeeks.org/problems/merge-k-sorted-linked-lists/1?itm_source=geeksforgeeks&itm_medium=article&itm_campaign=practice_card)
6+
7+
![image](https://github.com/user-attachments/assets/f332843f-9091-43a1-81a9-37d793c2261a)
8+
![image](https://github.com/user-attachments/assets/cffa6b9a-0c20-4c56-8708-ea9fda1e91be)
9+
10+
## Problem Explanation
11+
Given `K` sorted linked lists, we need to merge them into a single sorted linked list. The merged linked list should contain all elements from the original lists, in sorted order.
12+
13+
**Example**:
14+
Suppose we have the following 3 sorted linked lists:
15+
16+
- `List 1: 1 -> 4 -> 7`
17+
- `List 2: 2 -> 5 -> 8`
18+
- `List 3: 3 -> 6 -> 9`
19+
20+
After merging, the final sorted linked list should be:
21+
`1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9`
22+
23+
### Approach:
24+
25+
To solve this problem, we can use a **Divide and Conquer** approach:
26+
27+
1. **Divide** the lists into two halves recursively until each half contains only one list.
28+
2. **Conquer** by merging two lists at a time until we obtain one final merged list.
29+
30+
In each merge operation:
31+
- We compare elements from two lists (`l1` and `l2`) and attach the smaller element to the merged list.
32+
- We continue this process until all elements from both lists are merged in sorted order.
33+
34+
## Problem Solution
35+
```cpp
36+
class Solution {
37+
public:
38+
Node* mergeTwoLists(Node* l1, Node* l2){
39+
Node* temp = new Node(0);
40+
Node* current = temp;
41+
42+
while(l1 != NULL && l2 != NULL){
43+
if(l1 -> data < l2 -> data){
44+
current -> next = l1;
45+
l1 = l1 -> next;
46+
}else{
47+
current -> next = l2;
48+
l2 = l2 -> next;
49+
}
50+
51+
current = current -> next;
52+
}
53+
54+
if(l1 != NULL) current -> next = l1;
55+
if(l2 != NULL) current -> next = l2;
56+
57+
return temp -> next;
58+
};
59+
60+
Node* mergeKListsHelper(vector<Node*>& arr, int left, int right){
61+
if(left == right) return arr[left];
62+
63+
int mid = left + (right - left) / 2;
64+
65+
Node* leftMerge = mergeKListsHelper(arr, left, mid);
66+
Node* rightMerge = mergeKListsHelper(arr, mid+1, right);
67+
68+
return mergeTwoLists(leftMerge, rightMerge);
69+
};
70+
71+
Node* mergeKLists(vector<Node*>& arr) {
72+
if(arr.empty()) return NULL;
73+
74+
return mergeKListsHelper(arr, 0, arr.size() -1);
75+
}
76+
};
77+
```
78+
79+
## Problem Solution Explanation
80+
81+
The solution is structured with helper functions to divide and merge the lists. Here’s the code with detailed explanations:
82+
83+
```cpp
84+
class Solution {
85+
public:
86+
Node* mergeTwoLists(Node* l1, Node* l2){
87+
Node* temp = new Node(0);
88+
Node* current = temp;
89+
```
90+
91+
1. **Explanation**:
92+
- The `mergeTwoLists` function takes two sorted linked lists (`l1` and `l2`) and merges them.
93+
- A temporary node `temp` is created to serve as the starting point for the merged list.
94+
- `current` is a pointer that will traverse and build the merged list.
95+
96+
97+
98+
```cpp
99+
while(l1 != NULL && l2 != NULL){
100+
if(l1 -> data < l2 -> data){
101+
current -> next = l1;
102+
l1 = l1 -> next;
103+
}else{
104+
current -> next = l2;
105+
l2 = l2 -> next;
106+
}
107+
108+
current = current -> next;
109+
}
110+
```
111+
112+
2. **Explanation**:
113+
- We iterate through both lists while both have elements.
114+
- In each iteration:
115+
- If the `data` of `l1` is less than `l2`, we attach `l1` to the `current` node.
116+
- Otherwise, we attach `l2` to `current`.
117+
- We move `current` to the newly attached node.
118+
119+
120+
121+
```cpp
122+
if(l1 != NULL) current -> next = l1;
123+
if(l2 != NULL) current -> next = l2;
124+
125+
return temp -> next;
126+
};
127+
```
128+
129+
3. **Explanation**:
130+
- After the loop, if either list has remaining elements, we attach it to the end of the merged list.
131+
- Finally, we return `temp -> next` (skipping the initial placeholder node) as the head of the merged sorted list.
132+
133+
134+
135+
```cpp
136+
Node* mergeKListsHelper(vector<Node*>& arr, int left, int right){
137+
if(left == right) return arr[left];
138+
139+
int mid = left + (right - left) / 2;
140+
141+
Node* leftMerge = mergeKListsHelper(arr, left, mid);
142+
Node* rightMerge = mergeKListsHelper(arr, mid+1, right);
143+
144+
return mergeTwoLists(leftMerge, rightMerge);
145+
};
146+
```
147+
148+
4. **Explanation**:
149+
- `mergeKListsHelper` is a recursive helper function to merge lists in the range `left` to `right`.
150+
- **Base case**: If there is only one list in the range, return it directly.
151+
- **Recursive case**:
152+
- Find the middle index, `mid`, to divide the range.
153+
- Recursively merge the left half (`leftMerge`) and right half (`rightMerge`).
154+
- Merge the results of the left and right halves using `mergeTwoLists` and return the merged result.
155+
156+
157+
158+
```cpp
159+
Node* mergeKLists(vector<Node*>& arr) {
160+
if(arr.empty()) return NULL;
161+
162+
return mergeKListsHelper(arr, 0, arr.size() -1);
163+
}
164+
};
165+
```
166+
167+
5. **Explanation**:
168+
- The main function `mergeKLists` starts the merging process.
169+
- If `arr` (the vector of linked list heads) is empty, it returns `NULL`.
170+
- Otherwise, it calls `mergeKListsHelper` with the full range of lists (`0` to `arr.size() - 1`) and returns the merged result.
171+
172+
173+
174+
### Step 3: Example Walkthrough
175+
176+
**Example**:
177+
Input:
178+
```cpp
179+
arr = [
180+
List 1: 1 -> 4 -> 7,
181+
List 2: 2 -> 5 -> 8,
182+
List 3: 3 -> 6 -> 9
183+
]
184+
```
185+
186+
Process:
187+
1. We divide the lists using `mergeKListsHelper`:
188+
- First, split `[List 1, List 2, List 3]` into `[List 1]` and `[List 2, List 3]`.
189+
- Then, further split `[List 2, List 3]` into `[List 2]` and `[List 3]`.
190+
191+
2. Begin merging back:
192+
- Merge `List 2` and `List 3` to get `2 -> 3 -> 5 -> 6 -> 8 -> 9`.
193+
- Merge `List 1` with the merged result from the previous step.
194+
195+
Final merged result:
196+
`1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9`
197+
198+
Output:
199+
`1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9`
200+
201+
202+
203+
### Step 4: Time and Space Complexity
204+
205+
1. **Time Complexity**:
206+
- Merging two lists of combined length `N` takes `O(N)`.
207+
- With `K` lists, we’re performing `log K` levels of merge operations.
208+
- Each level involves merging `K/2`, `K/4`, etc., lists.
209+
- The total time complexity is `O(N * log K)`, where `N` is the total number of nodes in all lists.
210+
211+
2. **Space Complexity**:
212+
- The space complexity is `O(log K)` for the recursion stack in `mergeKListsHelper`.
213+
- Additionally, `O(K)` space is required for storing the list heads in the `arr` vector.
214+
215+
### Step 5: Additional Recommendations
216+
217+
- **Practice Similar Problems**: Understanding merging in linked lists is essential. Try merging two sorted lists or merging arrays to strengthen your concepts.
218+
- **Understand Divide and Conquer**: This problem is a good example of the divide-and-conquer technique. Understanding this will help you tackle similar problems more efficiently.
219+
- **Test Edge Cases**: Handle cases with empty lists, single-element lists, or all elements being the same. This helps in creating robust solutions.
220+
221+
This detailed breakdown should provide a thorough understanding of the solution, from problem approach to code execution.

0 commit comments

Comments
 (0)