Skip to content

Commit 0cd81bc

Browse files
solve task 23
1 parent b674d8d commit 0cd81bc

3 files changed

Lines changed: 182 additions & 0 deletions

File tree

PROGRESS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
| leetcode | medium | 0560. subarray sum equals k | Java | [Solution.java](leetcode/java/medium/0560-subarray-sum-equals-k/Solution.java) | [notes.md](leetcode/java/medium/0560-subarray-sum-equals-k/notes.md) |
1717
| leetcode | medium | 0567. permutation in string | Java | [Solution.java](leetcode/java/medium/0567-permutation-in-string/Solution.java) | [notes.md](leetcode/java/medium/0567-permutation-in-string/notes.md) |
1818
| leetcode | medium | 1493. longest subarray of 1s after deleting one element | Java | [Solution.java](leetcode/java/medium/1493-longest-subarray-of-1s-after-deleting-one-element/Solution.java) | [notes.md](leetcode/java/medium/1493-longest-subarray-of-1s-after-deleting-one-element/notes.md) |
19+
| leetcode | hard | 0023. merge k sorted lists | Java | [Solution.java](leetcode/java/hard/0023-merge-k-sorted-lists/Solution.java) | [notes.md](leetcode/java/hard/0023-merge-k-sorted-lists/notes.md) |
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Definition for singly-linked list.
3+
* public class ListNode {
4+
* int val;
5+
* ListNode next;
6+
* ListNode() {}
7+
* ListNode(int val) { this.val = val; }
8+
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
9+
* }
10+
*/
11+
class Solution {
12+
public ListNode merge(ListNode l1, ListNode l2){
13+
ListNode dummyHead = new ListNode();
14+
ListNode p = dummyHead;
15+
while(l1 != null && l2 != null){
16+
if(l1.val < l2.val){
17+
p.next = l1;
18+
l1 = l1.next;
19+
}else{
20+
p.next = l2;
21+
l2 = l2.next;
22+
}
23+
p = p.next;
24+
}
25+
p.next = (l1 != null) ? l1 : l2;
26+
return dummyHead.next;
27+
}
28+
29+
public ListNode mergeKLists(ListNode[] lists) {
30+
if(lists == null || lists.length == 0) {
31+
return null;
32+
}
33+
int interval = 1;
34+
while(interval < lists.length){
35+
for(int i = 0; i + interval < lists.length; i += interval * 2){
36+
lists[i] = merge(lists[i], lists[i+interval]);
37+
}
38+
interval *= 2;
39+
}
40+
return lists[0];
41+
}
42+
43+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# 23. Merge k Sorted Lists
2+
3+
## link
4+
LeetCode: https://leetcode.com/problems/merge-k-sorted-lists/
5+
6+
## Pattern
7+
8+
* Linked List
9+
* Divide and Conquer
10+
* Merge Sort
11+
12+
## Idea
13+
### Rus
14+
Требуется объединить `k` отсортированных связных списков в один отсортированный список.
15+
16+
Наивный подход — последовательно мержить каждый список с результатом предыдущих объединений. Однако в этом случае один и тот же узел может участвовать в слиянии много раз, что приводит к сложности около `O(N * k)`.
17+
18+
Вместо этого используется подход **Divide and Conquer**, аналогичный Merge Sort.
19+
20+
Сначала объединяются соседние списки попарно:
21+
22+
```text
23+
L1 + L2
24+
L3 + L4
25+
L5 + L6
26+
...
27+
```
28+
29+
После первого прохода количество списков уменьшается примерно вдвое.
30+
31+
Затем объединяются уже полученные результаты:
32+
33+
```text
34+
(L1+L2) + (L3+L4)
35+
(L5+L6) + (L7+L8)
36+
...
37+
```
38+
39+
Размер объединяемых групп удваивается на каждой итерации. Для этого используется переменная `interval`:
40+
41+
```text
42+
interval = 1
43+
interval = 2
44+
interval = 4
45+
interval = 8
46+
...
47+
```
48+
49+
На каждом шаге выполняется:
50+
51+
```java
52+
lists[i] = merge(lists[i], lists[i + interval]);
53+
```
54+
55+
Пока `interval` не станет больше количества списков.
56+
57+
Для объединения двух отсортированных списков используется стандартный алгоритм с dummy-узлом и двумя указателями.
58+
59+
В результате каждый уровень обработки проходит по всем узлам один раз, а количество уровней равно `log(k)`.
60+
61+
### Eng
62+
63+
We need to merge `k` sorted linked lists into a single sorted list.
64+
65+
A naive approach is to merge the lists one by one into a growing result. However, this causes the same nodes to be processed multiple times, resulting in roughly `O(N * k)` complexity.
66+
67+
Instead, we use a **Divide and Conquer** strategy similar to Merge Sort.
68+
69+
First, we merge adjacent pairs of lists:
70+
71+
```text
72+
L1 + L2
73+
L3 + L4
74+
L5 + L6
75+
...
76+
```
77+
78+
After the first pass, the number of lists is reduced by approximately half.
79+
80+
Then we merge the merged results:
81+
82+
```text
83+
(L1+L2) + (L3+L4)
84+
(L5+L6) + (L7+L8)
85+
...
86+
```
87+
88+
The size of merged groups doubles after every iteration. This is controlled by the `interval` variable:
89+
90+
```text
91+
interval = 1
92+
interval = 2
93+
interval = 4
94+
interval = 8
95+
...
96+
```
97+
98+
At each step we perform:
99+
100+
```java
101+
lists[i] = merge(lists[i], lists[i + interval]);
102+
```
103+
104+
until `interval` becomes greater than or equal to the number of lists.
105+
106+
The helper `merge()` function merges two sorted linked lists using the standard dummy-node technique.
107+
108+
Since each level processes all nodes once and there are `log(k)` levels, the overall complexity is `O(N log k)`.
109+
110+
## Complexity
111+
112+
- Time: `O(N log k)`
113+
- Space: `O(1)`
114+
115+
where:
116+
117+
* `N` = total number of nodes across all lists
118+
* `k` = number of linked lists
119+
120+
## Problems
121+
122+
* Easy to forget the loop condition:
123+
124+
```java
125+
i + interval < lists.length
126+
```
127+
128+
otherwise an index out of bounds error may occur.
129+
130+
* Be careful not to create new nodes during merge. The solution should reuse existing nodes by updating `next` pointers.
131+
132+
* The final answer is stored in:
133+
134+
```java
135+
lists[0]
136+
```
137+
138+
after all merge rounds are completed.

0 commit comments

Comments
 (0)