链表
解决链表问题的通用思路可以分为以下几个步骤:
-
理解问题:首先要准确理解题目的要求,链表的类型(单链表、双链表等),以及是否有环。
-
确定算法策略:根据问题的类型,决定是使用双指针、递归、迭代、哈希表等策略。
-
边界条件处理:在编写代码之前,考虑链表为空、只有一个节点、只有两个节点等边界情况。
-
编写代码:根据选定的策略编写代码,注意指针的移动和条件判断。
-
测试用例:考虑各种可能的测试用例,包括边界情况,确保代码的鲁棒性。
下面是一些常见的链表问题和用 Go 语言编写的代码示例:
例 1:反转链表
反转链表是最基本的链表操作之一,可以用迭代或递归的方式来实现。
type ListNode struct {
Val int
Next *ListNode
}
func reverseList(head *ListNode) *ListNode {
var prev *ListNode
curr := head
for curr != nil {
nextTemp := curr.Next
curr.Next = prev
prev = curr
curr = nextTemp
}
return prev
}
例 2:检测链表中是否有环
使用快慢指针的方法,如果快指针最终追上慢指针,则链表中存在环。
func hasCycle(head *ListNode) bool {
if head == nil || head.Next == nil {
return false
}
slow := head
fast := head.Next
for fast != nil && fast.Next != nil {
if slow == fast {
return true
}
slow = slow.Next
fast = fast.Next.Next
}
return false
}
例 3:合并两个排序的链表
将两个已排序的链表合并为一个新的排序链表。
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
dummy := &ListNode{}
current := dummy
for l1 != nil && l2 != nil {
if l1.Val < l2.Val {
current.Next = l1
l1 = l1.Next
} else {
current.Next = l2
l2 = l2.Next
}
current = current.Next
}
if l1 != nil {
current.Next = l1
} else {
current.Next = l2
}
return dummy.Next
}
例 4:找到链表的中间节点
使用快慢指针找到链表的中间节点。
func middleNode(head *ListNode) *ListNode {
slow := head
fast := head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
return slow
}
在解决链表问题时,重要的是要熟练掌握指针的使用,理解每个节点和指针的关系,以及在操作过程中可能出现的边界情况。练习和理解这些基本问题后,对于更复杂的链表问题也会有很大帮助。