Skip to content

Commit 5d00773

Browse files
committed
Update code
1 parent 73cabe3 commit 5d00773

39 files changed

+1262
-1164
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525

2626
### 1. 基础数据结构与算法
2727

28-
- [x] [半年零基础到 LeetCode 300 题,我的算法学习方法论](https://dongxiaoran.com/algo/basic/intro/)
29-
- [x] [当我们谈论刷题时,到底在刷什么](https://dongxiaoran.com/algo/basic/how/)
30-
- [x] [一题顶四题,一道题掌握 LinkedList 的 Iterative](https://dongxiaoran.com/algo/basic/iterativelist/): [Code](src/main/java/algorithm/basic/iterative)
28+
- [x] 半年零基础到 LeetCode 300 题,我的算法学习方法论: ✅ [Post](https://dongxiaoran.com/algo/basic/intro/)
29+
- [x] 当我们谈论刷题时,到底在刷什么: ✅ [Post](https://dongxiaoran.com/algo/basic/how/)
30+
- [x] 一题顶四题,一道题掌握 LinkedList 的 Iterative: ✅ [Post](https://dongxiaoran.com/algo/basic/iterativelist/) ⭐️ [Code](src/main/java/algorithm/basic/iterative)
3131

3232
- [ ] Binary Search
3333

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,25 @@
11
package algorithm.basic.iterative;
22

3+
import datastrcture.*;
4+
5+
/**
6+
* Given one linked list, find the middle node of the linked list.
7+
* If there are even number of nodes, return the left middle one.
8+
*/
39
public class FindMiddleOfList {
10+
public ListNode findMiddle(ListNode head) {
11+
if (head == null || head.next == null) {
12+
return head;
13+
}
14+
15+
ListNode slow = head;
16+
ListNode fast = head;
17+
// odd number: slow stop at n+1, fast stop at 2n+1 -> fast.next = null
18+
// even number: slow stop at n, fast stop at 1+2(n-1)=2n-1 -> fast.next.next = null
19+
while (fast.next != null && fast.next.next != null) {
20+
slow = slow.next;
21+
fast = fast.next.next;
22+
}
23+
return slow;
24+
}
425
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,32 @@
11
package algorithm.basic.iterative;
22

3+
import datastrcture.*;
4+
5+
/**
6+
* Given two sorted lists, return the merged list of the given two lists.
7+
*/
38
public class MergeTwoSortedList {
9+
public ListNode mergeTwoList(ListNode one, ListNode two) {
10+
// use dummy head to handle the corner case
11+
ListNode dummy = new ListNode(0);
12+
ListNode tail = dummy;
13+
14+
while (one != null || two != null) {
15+
if (one.val < two.val) {
16+
tail.next = one;
17+
one = one.next;
18+
} else {
19+
tail.next = two;
20+
two = two.next;
21+
}
22+
tail = tail.next;
23+
}
24+
25+
if (one != null) {
26+
tail.next = one;
27+
} else {
28+
tail.next = two;
29+
}
30+
return dummy.next;
31+
}
432
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,67 @@
11
package algorithm.basic.iterative;
22

3+
import datastrcture.*;
4+
5+
/**
6+
* Given a singly linked list L_0 → L_1 → … → L_{n-1} → L_n
7+
* Reverse it to L_n → L_{n-1} → … → L_1 → L_0
8+
*/
39
public class ReorderList {
10+
public void reorderList(ListNode head) {
11+
if (head == null || head.next == null) {
12+
return;
13+
}
14+
ListNode mid = findMiddle(head);
15+
ListNode secondHead = reverseList(mid.next);
16+
mid.next = null; // de-link to avoid circle
17+
head = mergeTwoList(head, secondHead);
18+
}
19+
20+
private ListNode findMiddle(ListNode head) {
21+
// assumption: head is not null
22+
ListNode slow = head;
23+
ListNode fast = head;
24+
// odd number: slow stop at n+1, fast stop at 2n+1 -> fast.next = null
25+
// even number: slow stop at n, fast stop at 1+2(n-1)=2n-1 -> fast.next.next = null
26+
while (fast.next != null && fast.next.next != null) {
27+
slow = slow.next;
28+
fast = fast.next.next;
29+
}
30+
return slow;
31+
}
32+
33+
private ListNode reverseList(ListNode head) {
34+
// assumption: head is not null
35+
ListNode prev = null;
36+
ListNode cur = head;
37+
ListNode next = null;
38+
39+
while (cur != null) {
40+
next = cur.next;
41+
cur.next = prev;
42+
prev = cur;
43+
cur = next;
44+
}
45+
return prev;
46+
}
47+
48+
private ListNode mergeTwoList(ListNode one, ListNode two) {
49+
// use dummy head to handle the corner case, one is oddHead, two is evenHead
50+
ListNode dummy = new ListNode(0);
51+
ListNode tail = dummy;
52+
53+
while (one != null && two != null) {
54+
tail.next = one;
55+
one = one.next;
56+
tail.next.next = two;
57+
two = two.next;
58+
tail = tail.next.next;
59+
}
60+
61+
// first half sublist will be longer or equal than second half list
62+
if (one != null) {
63+
tail.next = one;
64+
}
65+
return dummy.next;
66+
}
467
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,25 @@
11
package algorithm.basic.iterative;
22

3+
import datastrcture.*;
4+
5+
/**
6+
* Given one single linked list, return the reversed list.
7+
*/
38
public class ReverseLinkedList {
9+
public ListNode reverseList(ListNode head) {
10+
if (head == null) {
11+
return null;
12+
}
13+
ListNode prev = null;
14+
ListNode cur = head;
15+
ListNode next = null;
16+
17+
while (cur != null) {
18+
next = cur.next;
19+
cur.next = prev;
20+
prev = cur;
21+
cur = next;
22+
}
23+
return prev;
24+
}
425
}
Lines changed: 104 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,126 @@
11
package algorithm.pointers.merge;
22

33
import datastrcture.ListNode;
4+
45
import java.util.*;
56

67
/**
78
* You are given an array of k linked lists, each is sorted in ascending order.
89
* Merge all the linked-lists into one sorted linked-list and return it.
910
*/
1011
public class MergeKSortedList {
11-
// Method 1: K Pointers Merge with MinHeap
12-
// Time: O(nK*logK), Space: O(K)
13-
public ListNode mergeKSortedList(ListNode[] lists) {
14-
if (lists == null || lists.length == 0) {
15-
return null;
16-
}
17-
18-
int k = lists.length;
19-
// keep k pointers to merge k list, each time move next the list with smallest
20-
// thus we can use a min heap with size k to compare the k pointers
21-
PriorityQueue<ListNode> minHeap = new PriorityQueue<>(k, (n1, n2) -> n1.val - n2.val);
22-
// initialize: add k head to the heap
23-
for (ListNode head : lists) {
24-
if (head != null) { // corner case: the k list may have null list
25-
minHeap.offer(head);
26-
}
12+
// Method 1: K Pointers Merge with MinHeap
13+
// Time: O(nK*logK), Space: O(K)
14+
public ListNode mergeKSortedList(ListNode[] lists) {
15+
if (lists == null || lists.length == 0) {
16+
return null;
17+
}
18+
19+
int k = lists.length;
20+
// keep k pointers to merge k list, each time move next the list with smallest
21+
// thus we can use a min heap with size k to compare the k pointers
22+
PriorityQueue<ListNode> minHeap = new PriorityQueue<>(k, (n1, n2) -> n1.val - n2.val);
23+
// initialize: add k head to the heap
24+
for (ListNode head : lists) {
25+
if (head != null) { // corner case: the k list may have null list
26+
minHeap.offer(head);
27+
}
28+
}
29+
30+
ListNode dummy = new ListNode(0);
31+
ListNode cur = dummy;
32+
33+
// each add the smallest node to the new list, and add next node into the heap
34+
while (!minHeap.isEmpty()) {
35+
ListNode node = minHeap.poll();
36+
if (node.next != null) { // added all the nodes of one list
37+
minHeap.offer(node.next);
38+
}
39+
cur.next = node;
40+
node.next = null;
41+
cur = node;
42+
}
43+
44+
return dummy.next;
2745
}
2846

29-
ListNode dummy = new ListNode(0);
30-
ListNode cur = dummy;
31-
32-
// each add the smallest node to the new list, and add next node into the heap
33-
while (!minHeap.isEmpty()) {
34-
ListNode node = minHeap.poll();
35-
if (node.next != null) { // added all the nodes of one list
36-
minHeap.offer(node.next);
37-
}
38-
cur.next = node;
39-
node.next = null;
40-
cur = node;
47+
// Method 2: Recursive Binary Reduction, Divide and Conquer
48+
// Time: O(nK*logK), Space: O(K) for call stack
49+
public ListNode mergeKSortedList1(ListNode[] lists) {
50+
if (lists == null || lists.length == 0) {
51+
return null;
52+
}
53+
return merge(lists, 0, lists.length - 1);
4154
}
4255

43-
return dummy.next;
44-
}
45-
46-
// Method 2: Recursive Binary Reduction, Divide and Conquer
47-
// Time: O(nK*logK), Space: O(K) for call stack
48-
public ListNode mergeKSortedList1(ListNode[] lists) {
49-
if (lists == null || lists.length == 0) {
50-
return null;
51-
}
52-
return merge(lists, 0, lists.length - 1);
53-
}
54-
55-
// return merged lists that range from start to end
56-
private ListNode merge(ListNode[] lists, int start, int end) {
57-
// base case
58-
if (start == end) { // the list itself
59-
return lists[start];
56+
// return merged lists that range from start to end
57+
private ListNode merge(ListNode[] lists, int start, int end) {
58+
// base case
59+
if (start == end) { // the list itself
60+
return lists[start];
61+
}
62+
63+
int mid = start + (end - start) / 2;
64+
ListNode left = merge(lists, start, mid);
65+
ListNode right = merge(lists, mid + 1, end);
66+
return mergeTwoList(left, right);
6067
}
6168

62-
int mid = start + (end - start) / 2;
63-
ListNode left = merge(lists, start, mid);
64-
ListNode right = merge(lists, mid + 1, end);
65-
return mergeTwoList(left, right);
66-
}
67-
68-
// Method 3: Iterative Binary Reduction
69-
// Time: O(nK*logK), Space: O(1)
70-
public ListNode mergeKSortedList2(ListNode[] lists) {
71-
if (lists == null || lists.length == 0) {
72-
return null;
69+
// Method 3: Iterative Binary Reduction
70+
// Time: O(nK*logK), Space: O(1)
71+
public ListNode mergeKSortedList2(ListNode[] lists) {
72+
if (lists == null || lists.length == 0) {
73+
return null;
74+
}
75+
76+
int k = lists.length;
77+
// reuse the list node array
78+
for (int interval = 1; interval < k; interval *= 2) {
79+
for (int i = 0; i < (k - interval); i += interval * 2) {
80+
lists[i] = mergeTwoList(lists[i], lists[i + interval]);
81+
}
82+
}
83+
return lists[0];
7384
}
7485

75-
int k = lists.length;
76-
// reuse the list node array
77-
for (int interval = 1; interval < k; interval *= 2) {
78-
for (int i = 0; i < (k - interval); i += interval * 2) {
79-
lists[i] = mergeTwoList(lists[i], lists[i + interval]);
80-
}
81-
}
82-
return lists[0];
83-
}
84-
85-
// Method 4: Iterative Merge Two List
86-
// Time: O(nK^2), Space: O(1)
87-
public ListNode mergeKSortedList3(ListNode[] lists) {
88-
if (lists == null || lists.length == 0) {
89-
return null;
86+
// Method 4: Iterative Merge Two List
87+
// Time: O(nK^2), Space: O(1)
88+
public ListNode mergeKSortedList3(ListNode[] lists) {
89+
if (lists == null || lists.length == 0) {
90+
return null;
91+
}
92+
93+
ListNode merged = lists[0];
94+
// for loop can cover the case that length == 1
95+
// if length = 1, the for loop will be i = 1 < 1, will not enter
96+
for (int i = 1; i < lists.length; i++) {
97+
merged = mergeTwoList(lists[i], merged);
98+
}
99+
100+
return merged;
90101
}
91102

92-
ListNode merged = lists[0];
93-
// for loop can cover the case that length == 1
94-
// if length = 1, the for loop will be i = 1 < 1, will not enter
95-
for (int i = 1; i < lists.length; i++) {
96-
merged = mergeTwoList(lists[i], merged);
97-
}
98-
99-
return merged;
100-
}
101-
102-
private ListNode mergeTwoList(ListNode head1, ListNode head2) {
103-
ListNode dummy = new ListNode(0);
104-
ListNode cur = dummy;
105-
106-
while (head1 != null && head2 != null) {
107-
if (head1.val < head2.val) {
108-
cur.next = head1;
109-
head1 = head1.next;
110-
} else {
111-
cur.next = head2;
112-
head2 = head2.next;
113-
}
114-
cur = cur.next;
115-
}
116-
117-
if (head1 != null) {
118-
cur.next = head1;
119-
}
120-
if (head2 != null) {
121-
cur.next = head2;
103+
private ListNode mergeTwoList(ListNode head1, ListNode head2) {
104+
ListNode dummy = new ListNode(0);
105+
ListNode cur = dummy;
106+
107+
while (head1 != null && head2 != null) {
108+
if (head1.val < head2.val) {
109+
cur.next = head1;
110+
head1 = head1.next;
111+
} else {
112+
cur.next = head2;
113+
head2 = head2.next;
114+
}
115+
cur = cur.next;
116+
}
117+
118+
if (head1 != null) {
119+
cur.next = head1;
120+
}
121+
if (head2 != null) {
122+
cur.next = head2;
123+
}
124+
return dummy.next;
122125
}
123-
return dummy.next;
124-
}
125126
}

0 commit comments

Comments
 (0)