mirror of
https://github.com/CyC2018/Interview-Notebook.git
synced 2026-10-26 12:53:43 +00:00
Update Leetcode 题解 - 链表.md
补充 K 个一组翻转链表、重排链表、合并 K 个有序链表、链表排序,并配图说明 K 个一组翻转时的指针变化。
This commit is contained in:
@@ -11,6 +11,10 @@
|
||||
* [8. 回文链表](#8-回文链表)
|
||||
* [9. 分隔链表](#9-分隔链表)
|
||||
* [10. 链表元素按奇偶聚集](#10-链表元素按奇偶聚集)
|
||||
* [11. K 个一组翻转链表](#11-k-个一组翻转链表)
|
||||
* [12. 重排链表](#12-重排链表)
|
||||
* [13. 合并 K 个有序链表](#13-合并-k-个有序链表)
|
||||
* [14. 链表排序](#14-链表排序)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -363,3 +367,170 @@ public ListNode oddEvenList(ListNode head) {
|
||||
return head;
|
||||
}
|
||||
```
|
||||
|
||||
## 11. K 个一组翻转链表
|
||||
|
||||
25\. Reverse Nodes in k-Group (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/reverse-nodes-in-k-group/) / [力扣](https://leetcode.cn/problems/reverse-nodes-in-k-group/)
|
||||
|
||||
```text
|
||||
Input: 1->2->3->4->5, k = 2
|
||||
Output: 2->1->4->3->5
|
||||
```
|
||||
|
||||
题目描述:每 k 个节点一组进行翻转,最后不足 k 个的节点保持原有顺序。
|
||||
|
||||
使用一个虚拟头节点 dummy,pre 指向下一组的前一个节点。先从 pre 向后走 k 步找到这一组的尾节点 tail,走不到说明剩余节点不足 k 个。然后把 pre.next 到 tail 这一段原地翻转,再把它接回原链表,最后 pre 移到这一组翻转后的末尾。
|
||||
|
||||
<div align="center"> <img src="pics/reverse-k-group.png" width="560px"/> </div><br>
|
||||
|
||||
```java
|
||||
public ListNode reverseKGroup(ListNode head, int k) {
|
||||
ListNode dummy = new ListNode(-1);
|
||||
dummy.next = head;
|
||||
ListNode pre = dummy;
|
||||
while (true) {
|
||||
ListNode tail = pre;
|
||||
for (int i = 0; i < k && tail != null; i++) {
|
||||
tail = tail.next;
|
||||
}
|
||||
if (tail == null) {
|
||||
break;
|
||||
}
|
||||
ListNode first = pre.next, next = tail.next;
|
||||
ListNode prev = next, cur = first;
|
||||
while (cur != next) {
|
||||
ListNode tmp = cur.next;
|
||||
cur.next = prev;
|
||||
prev = cur;
|
||||
cur = tmp;
|
||||
}
|
||||
pre.next = tail;
|
||||
pre = first;
|
||||
}
|
||||
return dummy.next;
|
||||
}
|
||||
```
|
||||
|
||||
## 12. 重排链表
|
||||
|
||||
143\. Reorder List (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/reorder-list/) / [力扣](https://leetcode.cn/problems/reorder-list/)
|
||||
|
||||
```text
|
||||
Input: 1->2->3->4->5
|
||||
Output: 1->5->2->4->3
|
||||
```
|
||||
|
||||
题目描述:把 L0→L1→…→Ln 重排为 L0→Ln→L1→Ln-1→…,只能修改节点的指针。
|
||||
|
||||
可以拆成三个已经解决过的子问题:用快慢指针找到中点并断开;把后半段反转;再把两段交替连接起来。
|
||||
|
||||
```java
|
||||
public void reorderList(ListNode head) {
|
||||
if (head == null || head.next == null) {
|
||||
return;
|
||||
}
|
||||
ListNode slow = head, fast = head;
|
||||
while (fast.next != null && fast.next.next != null) {
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
}
|
||||
ListNode l2 = reverse(slow.next);
|
||||
slow.next = null;
|
||||
ListNode l1 = head;
|
||||
while (l2 != null) {
|
||||
ListNode n1 = l1.next, n2 = l2.next;
|
||||
l1.next = l2;
|
||||
l2.next = n1;
|
||||
l1 = n1;
|
||||
l2 = n2;
|
||||
}
|
||||
}
|
||||
|
||||
private ListNode reverse(ListNode head) {
|
||||
ListNode pre = null;
|
||||
while (head != null) {
|
||||
ListNode next = head.next;
|
||||
head.next = pre;
|
||||
pre = head;
|
||||
head = next;
|
||||
}
|
||||
return pre;
|
||||
}
|
||||
```
|
||||
|
||||
## 13. 合并 K 个有序链表
|
||||
|
||||
23\. Merge k Sorted Lists (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/merge-k-sorted-lists/) / [力扣](https://leetcode.cn/problems/merge-k-sorted-lists/)
|
||||
|
||||
用小顶堆保存每个链表当前的头节点,每次取出值最小的节点接到结果链表后面,再把它的下一个节点放入堆中。设一共有 N 个节点,每个节点进出堆一次,时间复杂度为 O(NlogK)。
|
||||
|
||||
也可以像归并排序那样两两合并,时间复杂度同样是 O(NlogK)。
|
||||
|
||||
```java
|
||||
public ListNode mergeKLists(ListNode[] lists) {
|
||||
PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> Integer.compare(a.val, b.val));
|
||||
for (ListNode node : lists) {
|
||||
if (node != null) {
|
||||
pq.add(node);
|
||||
}
|
||||
}
|
||||
ListNode dummy = new ListNode(-1), tail = dummy;
|
||||
while (!pq.isEmpty()) {
|
||||
ListNode node = pq.poll();
|
||||
tail.next = node;
|
||||
tail = node;
|
||||
if (node.next != null) {
|
||||
pq.add(node.next);
|
||||
}
|
||||
}
|
||||
return dummy.next;
|
||||
}
|
||||
```
|
||||
|
||||
## 14. 链表排序
|
||||
|
||||
148\. Sort List (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/sort-list/) / [力扣](https://leetcode.cn/problems/sort-list/)
|
||||
|
||||
题目描述:在 O(NlogN) 时间复杂度内对链表进行排序。
|
||||
|
||||
链表不能随机访问,适合用归并排序:用快慢指针找到中点断开,两半分别排序后,用第 3 题的方法归并。递归需要 O(logN) 的栈空间。
|
||||
|
||||
```java
|
||||
public ListNode sortList(ListNode head) {
|
||||
if (head == null || head.next == null) {
|
||||
return head;
|
||||
}
|
||||
ListNode slow = head, fast = head.next;
|
||||
while (fast != null && fast.next != null) {
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
}
|
||||
ListNode right = slow.next;
|
||||
slow.next = null;
|
||||
return merge(sortList(head), sortList(right));
|
||||
}
|
||||
|
||||
private ListNode merge(ListNode l1, ListNode l2) {
|
||||
ListNode dummy = new ListNode(-1), tail = dummy;
|
||||
while (l1 != null && l2 != null) {
|
||||
if (l1.val <= l2.val) {
|
||||
tail.next = l1;
|
||||
l1 = l1.next;
|
||||
} else {
|
||||
tail.next = l2;
|
||||
l2 = l2.next;
|
||||
}
|
||||
tail = tail.next;
|
||||
}
|
||||
tail.next = l1 != null ? l1 : l2;
|
||||
return dummy.next;
|
||||
}
|
||||
```
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
@@ -0,0 +1,95 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="300" viewBox="0 0 600 300">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.sub { font-size: 11px; fill: #888; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #666; stroke-width: 1.3; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #C0C0C0; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#C0605A" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#6A9F68" stroke-width="1.6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="300" y="28" class="title">K 个一组翻转链表(k = 2)</text>
|
||||
<text x="20" y="90" class="b">翻转前</text>
|
||||
<rect x="88" y="72" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="85" y="69" width="50" height="32" rx="6" fill="#E6E6E6"/>
|
||||
<text x="110" y="89.5" class="c b">dummy</text>
|
||||
<line x1="137" y1="85" x2="163" y2="85" class="arrow "/>
|
||||
<rect x="168" y="72" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="165" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="190" y="89.5" class="c b">1</text>
|
||||
<line x1="217" y1="85" x2="243" y2="85" class="arrow "/>
|
||||
<rect x="248" y="72" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="245" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="270" y="89.5" class="c b">2</text>
|
||||
<line x1="297" y1="85" x2="323" y2="85" class="arrow "/>
|
||||
<rect x="328" y="72" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="325" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="350" y="89.5" class="c b">3</text>
|
||||
<line x1="377" y1="85" x2="403" y2="85" class="arrow "/>
|
||||
<rect x="408" y="72" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="405" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="430" y="89.5" class="c b">4</text>
|
||||
<line x1="457" y1="85" x2="483" y2="85" class="arrow "/>
|
||||
<rect x="488" y="72" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="485" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="510" y="89.5" class="c b">5</text>
|
||||
<line x1="110" y1="131" x2="110" y2="105" class="arrow "/>
|
||||
<text x="110" y="147" class="c ">pre</text>
|
||||
<line x1="190" y1="131" x2="190" y2="105" class="arrow "/>
|
||||
<text x="190" y="147" class="c ">first</text>
|
||||
<line x1="270" y1="131" x2="270" y2="105" class="arrow "/>
|
||||
<text x="270" y="147" class="c ">tail</text>
|
||||
<line x1="350" y1="131" x2="350" y2="105" class="arrow "/>
|
||||
<text x="350" y="147" class="c ">next</text>
|
||||
<text x="20" y="205" class="b">翻转后</text>
|
||||
<rect x="88" y="187" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="85" y="184" width="50" height="32" rx="6" fill="#E6E6E6"/>
|
||||
<text x="110" y="204.5" class="c b">dummy</text>
|
||||
<line x1="137" y1="200" x2="163" y2="200" class="arrow "/>
|
||||
<rect x="168" y="187" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="165" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="190" y="204.5" class="c b">2</text>
|
||||
<line x1="217" y1="200" x2="243" y2="200" class="arrow "/>
|
||||
<rect x="248" y="187" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="245" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="270" y="204.5" class="c b">1</text>
|
||||
<line x1="297" y1="200" x2="323" y2="200" class="arrow "/>
|
||||
<rect x="328" y="187" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="325" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="350" y="204.5" class="c b">3</text>
|
||||
<line x1="377" y1="200" x2="403" y2="200" class="arrow "/>
|
||||
<rect x="408" y="187" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="405" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="430" y="204.5" class="c b">4</text>
|
||||
<line x1="457" y1="200" x2="483" y2="200" class="arrow "/>
|
||||
<rect x="488" y="187" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="485" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="510" y="204.5" class="c b">5</text>
|
||||
<line x1="110" y1="246" x2="110" y2="220" class="arrow "/>
|
||||
<text x="110" y="262" class="c ">pre.next = tail</text>
|
||||
<line x1="270" y1="246" x2="270" y2="220" class="arrow green"/>
|
||||
<text x="270" y="262" class="c ok">pre = first</text>
|
||||
<text x="300" y="292" class="c sub">first 成为这一组的末尾,也是下一组的 pre</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
Reference in New Issue
Block a user