「算」 03. 链表

本文最后更新于:1 分钟前

Golang 链表相关题目。

1 链表

1.1 类型

  • 单链表

  • 双链表

  • 循环链表

1.2 存储方式

链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

1.3 操作

  • 定义
1
2
3
4
type ListNode struct {
Val int
Next *ListNode
}
  • 删除

建议使用虚拟头节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func removeElements(head *ListNode, val int) *ListNode {
dmHead := &ListNode{}
dmHead.Next = head
cur, pre := head, dmHead
for cur != nil {
if cur.Val == val {
pre.Next = cur.Next
} else {
pre = pre.Next
}
cur = cur.Next
}
return dmHead.Next
}
  • 添加

1.4 性能分析

2 题目

2.1 leetcode 24 题

两两交换链表中的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
func swapPairs(head *ListNode) *ListNode {
dmHead := &ListNode{Next: head}
pre, cur := dmHead, head
for cur != nil && cur.Next != nil {
next := cur.Next.Next
pre.Next = cur.Next
cur.Next.Next = cur
cur.Next = next
pre = cur
cur = next
}
return dmHead.Next
}

2.2 leetcode 19 题

删除倒数第 N 个节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func removeNthFromEnd(head *ListNode, n int) *ListNode {
var count int
dmHead := &ListNode{Next: head}
pre, cur := dmHead, head
for cur != nil {
if count != n {
count++
} else {
pre = pre.Next
}
cur = cur.Next
}
pre.Next = pre.Next.Next
return dmHead.Next
}

2.3 leetcode 160 题

给你两个单链表的头节点 headA 和 headB,请你找出并返回两个单链表相交的起始节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
func getIntersectionNode1(headA, headB *ListNode) *ListNode {
vis := map[*ListNode]bool{}
for tmp := headA; tmp != nil; tmp = tmp.Next {
vis[tmp] = true
}
for tmp := headB; tmp != nil; tmp = tmp.Next {
if vis[tmp] {
return tmp
}
}
return nil
}

func getIntersectionNode2(headA, headB *ListNode) *ListNode {
curA := headA
curB := headB
lenA, lenB := 0, 0
// 求 A,B 的长度
for curA != nil {
curA = curA.Next
lenA++
}
for curB != nil {
curB = curB.Next
lenB++
}
var step int
var fast, slow *ListNode
// 求长度差,并且让更长的链表先走相差的长度
if lenA > lenB {
step = lenA - lenB
fast, slow = headA, headB
} else {
step = lenB - lenA
fast, slow = headB, headA
}
for i := 0; i < step; i++ {
fast = fast.Next
}
// 遍历两个链表遇到相同则跳出遍历
for fast != slow {
fast = fast.Next
slow = slow.Next
}
return fast
}

2.4 leetcode 142 题

判断链表中是否有环,返回链表开始入环的第一个节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func detectCycle(head *ListNode) *ListNode {
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
for slow != head {
slow = slow.Next
head = head.Next
}
return head
}
}
return nil
}

2.5 leetcode 206 题

反转链表。

注意申明 pre 的时候不可以用 pre := &ListNode{},否则其值是 0 而不是 nil。

1
2
3
4
5
6
7
8
9
10
11
12
func reverseList(head *ListNode) *ListNode {
var pre *ListNode
cur := head

for cur != nil {
next := cur.Next
cur.Next = pre
pre = cur
cur = next
}
return pre
}

2.5 leetcode 146 题

LRU 缓存。

哈希表 + 双向链表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
type LRUCache struct {
cp, size int
rec map[int]*Node
head, tail *Node
}

type Node struct {
Key, Val int
Pre, Next *Node
}

func Constructor(capacity int) LRUCache {
r := make(map[int]*Node)
h, t := &Node{}, &Node{}
h.Next = t
t.Pre = h
newLRU := LRUCache {cp: capacity, size: 0, rec: r, head: h, tail: t}
return newLRU
}

func (this *LRUCache) Get(key int) int {
node, exist := this.rec[key]
if exist {
this.removeNode(node)
this.addToHead(node)
return node.Val
}
return -1
}

func (this *LRUCache) Put(key int, value int) {
node, exist := this.rec[key]
if exist {
this.rec[key].Val = value
this.removeNode(node)
this.addToHead(node)
} else {
node = &Node{Key: key, Val: value}
this.rec[key] = node
if this.size == this.cp {
delete(this.rec, this.tail.Pre.Key)
this.removeTail()
} else {
this.size++
}
this.addToHead(node)
}
}

func (this *LRUCache) addToHead(node *Node) {
nx := this.head.Next
this.head.Next = node
node.Next = nx
nx.Pre = node
node.Pre = this.head
}

func (this *LRUCache) removeNode(node *Node) {
pr, nx := node.Pre, node.Next
pr.Next = nx
nx.Pre = pr
}

func (this *LRUCache) removeTail() {
this.removeNode(this.tail.Pre)
}

「算」 03. 链表
https://qanlyma.github.io/Algorithm-list/
作者
Qanly
发布于
2023年3月15日