parent
72f66183fe
commit
e8f43870ae
@ -0,0 +1,206 @@ |
||||
--- |
||||
链表 |
||||
--- |
||||
|
||||
#### 目录 |
||||
|
||||
1. 链表分类 |
||||
- 单链表 |
||||
- 循环链表 |
||||
- 双向链表 |
||||
- 双向循环链表 |
||||
2. 常见链表算法题 |
||||
- 单链表反转 |
||||
- 链表中环的检测 |
||||
- 两个有序链表的合并 |
||||
- 删除链表倒数第 n 个结点 |
||||
- 求链表的中间结点 |
||||
3. 总结 |
||||
|
||||
#### 链表分类 |
||||
|
||||
##### 单链表 |
||||
|
||||
![](https://i.loli.net/2019/02/25/5c73a3d48b8f4.jpg) |
||||
|
||||
##### 循环链表 |
||||
|
||||
![](https://i.loli.net/2019/02/25/5c73a4202fc70.jpg) |
||||
|
||||
##### 双向链表 |
||||
|
||||
![](https://i.loli.net/2019/02/25/5c73a435a1dd8.jpg) |
||||
|
||||
##### 双向循环链表 |
||||
|
||||
![](https://i.loli.net/2019/02/25/5c73a44c30c40.jpg) |
||||
|
||||
#### 常见链表算法题 |
||||
|
||||
1. 单链表的反转 |
||||
|
||||
```java |
||||
public class LinkedListDemo { |
||||
|
||||
private static Node head; |
||||
|
||||
public static void main(String[] args) { |
||||
head = new Node(0); |
||||
head.next = new Node(1); |
||||
head.next.next = new Node(2); |
||||
head.next.next.next = new Node(3); |
||||
|
||||
reverseLinkedList(); |
||||
|
||||
while (head != null) { |
||||
System.out.println(head.value); |
||||
head = head.next; |
||||
} |
||||
} |
||||
|
||||
//单链表的反转 |
||||
private static void reverseLinkedList() { |
||||
if (head == null || head.next == null) { |
||||
return; |
||||
} |
||||
Node p1 = head; |
||||
Node p2 = head.next; |
||||
Node p3 = null; |
||||
while (p2 != null) { |
||||
p3 = p2.next; |
||||
p2.next = p1; |
||||
p1 = p2; |
||||
p2 = p3; |
||||
} |
||||
head.next = null; |
||||
head = p1; |
||||
} |
||||
|
||||
static class Node { |
||||
int value; |
||||
Node next; |
||||
|
||||
Node(int value) { |
||||
this.value = value; |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
参考:[漫画:如何将一个链表“逆序”?](https://mp.weixin.qq.com/s/MR_qAbonFqGF_ljeWUC26w) |
||||
|
||||
2. 链表中环的检测 |
||||
|
||||
这道题有三种解法: |
||||
|
||||
```java |
||||
public class LinkedListDemo { |
||||
|
||||
private static Node head; |
||||
|
||||
public static void main(String[] args) { |
||||
head = new Node(0); |
||||
head.next = new Node(1); |
||||
head.next.next = new Node(2); |
||||
head.next.next.next = new Node(3); |
||||
head.next.next.next.next = head.next; |
||||
|
||||
boolean isHasCycleBySet = hasCycleBySet(); |
||||
System.out.println(isHasCycleBySet); |
||||
boolean isHasCycleByRun = hasCycleByRun(); |
||||
System.out.println(isHasCycleByRun); |
||||
boolean isHasCycleByMagic = hasCycleByMagic(); |
||||
System.out.println(isHasCycleByMagic); |
||||
} |
||||
|
||||
//用 HashSet 判断 |
||||
private static boolean hasCycleBySet() { |
||||
if (head == null || head.next == null) { |
||||
return false; |
||||
} |
||||
Set<Node> set = new HashSet<>(); |
||||
while (head != null) { |
||||
if (set.contains(head)) { |
||||
return true; |
||||
} else { |
||||
set.add(head); |
||||
} |
||||
head = head.next; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
//快慢指针 |
||||
private static boolean hasCycleByRun() { |
||||
if (head == null || head.next == null) { |
||||
return false; |
||||
} |
||||
Node p1 = head; |
||||
Node p2 = head.next; |
||||
while (p1 != p2) { |
||||
if (p2 == null || p2.next == null) { |
||||
return false; |
||||
} |
||||
p1 = p1.next; |
||||
p2 = p2.next.next; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
//魔法数解法 |
||||
private static boolean hasCycleByMagic() { |
||||
if (head == null || head.next == null) { |
||||
return false; |
||||
} |
||||
while (head != null) { |
||||
if (head.value == 2 << 30) { |
||||
return true; |
||||
} else { |
||||
head.value = 2 << 30; |
||||
} |
||||
head = head.next; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
static class Node { |
||||
int value; |
||||
Node next; |
||||
|
||||
Node(int value) { |
||||
this.value = value; |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
3. 两个有序链表的合并 |
||||
|
||||
```java |
||||
|
||||
``` |
||||
|
||||
4. 删除链表倒数第 n 个结点 |
||||
|
||||
```java |
||||
|
||||
``` |
||||
|
||||
5. 求链表的中间结点 |
||||
|
||||
```java |
||||
|
||||
``` |
||||
|
||||
|
||||
|
||||
#### 总结 |
||||
|
||||
面试中手写算法题最多的就是链表相关的,链表算法到底难不难?难?难得话一个题再写十遍还难不难?(气急败坏中... |
||||
|
||||
不过,链表中需要注意几个边界条件: |
||||
|
||||
1. 如果链表为空 |
||||
2. 如果链表只有一个结点时 |
||||
3. 如果链表只有两个结点时 |
||||
4. 代码逻辑在处理头结点和尾结点时 |
After Width: | Height: | Size: 141 KiB |
Before Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 39 KiB |
Loading…
Reference in new issue