总的来说,链表的题目往往只会在面试题中出现,思维难度不大,现场debug的能力要求较高。除了个别比较难的题目,一般都不难.
链表的题目要熟悉常用编码技巧,设置空头节点dummy,避免边界情况的处理
熟悉反转链表这种较难的编码题目
熟悉快慢指针技巧
Leetcode19 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
快慢指针,使用dummy处理边界情况。
func removeNthFromEnd(head *ListNode, n int) *ListNode {
dummy := &ListNode{Next: head}
fast, slow, index := dummy, dummy, 0
for index < n+1{
fast = fast.Next
index++
}
for fast!=nil{
fast = fast.Next
slow = slow.Next
}
slow.Next = slow.Next.Next
return dummy.Next
}
Leetcode 237
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:
示例 1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
脑经急转弯的题目,已经说明了不是尾节点,所以交换值,删除后面的节点。
func deleteNode(node *ListNode) {
node.Val = node.Next.Val
node.Next = node.Next.Next
}
Leetcode 83. 删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
双指针思想,必会题目
func deleteDuplicates(head *ListNode) *ListNode {
cur := head
for cur!=nil && cur.Next!=nil{
if(cur.Next.Val == cur.Val){
cur.Next = cur.Next.Next
}else{
cur = cur.Next
}
}
return head
}
Leetcode 61. 旋转链表
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
遍历到链表末尾,结成换,再合适位置断开,模拟思想
func rotateRight(head *ListNode, k int) *ListNode {
cur, n := head, 1
if cur==nil{
return cur
}
for cur.Next!=nil{
cur = cur.Next
n++
}
//n++
cur.Next = head
cur = head
m := n-1-k%n
for i:=0;i
Leetcode 24 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
这道题目比较难,建议采用递归的思路
func swapPairs(head *ListNode) *ListNode {
if head==nil || head.Next == nil{
return head
}
next := head.Next
head.Next = swapPairs(next.Next)
next.Next = head
return next
}
Leetcode 206. 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
这是一道必会的题目,建议采用三根指针逐一反转的办法
func reverseList(head *ListNode) *ListNode {
var pre *ListNode = nil
cur:= head
for cur!=nil{
next := cur.Next
cur.Next = pre
pre = cur
cur = next
}
return pre
}
Leetcode 92. 反转链表 II
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
这道题目比上面那道题目要更难一点, 这里还是要使用dummy
func reverseBetween(head *ListNode, m int, n int) *ListNode {
if m == n{
return head
}
dummy := &ListNode{Next: head}
p := dummy
for i:=0;i
Leetcode 160. 相交链表
这个是一道巧妙解法的题目,比较简单
func getIntersectionNode(headA, headB *ListNode) *ListNode {
curA, curB := headA, headB
lenA, lenB := 0, 0
for curA!=nil || curB!=nil{
if curA!=nil{
curA = curA.Next
lenA++
}
if curB!=nil{
curB = curB.Next
lenB++
}
}
curA, curB = headA, headB
if lenA>lenB{
for i:=0;i
Leetcode 142. 环形链表 II
func detectCycle(head *ListNode) *ListNode {
hasCircle := false
fast, slow := head, head
for fast!=nil && fast.Next!=nil && slow!=nil{
fast = fast.Next.Next
slow = slow.Next
if slow == fast{
hasCircle = true
break
}
}
if !hasCircle{
return nil
}
slow = head
for slow!=fast{
slow = slow.Next
fast = fast.Next
}
return slow
}
对一个链表进行排序,可以使用归并排序,空间复杂度就是O(1), 会涉及到找链表中点的操作,使用快慢指针进行
func sortList(head *ListNode) *ListNode {
if head==nil || head.Next == nil{
return head
}
slow, fast := head, head.Next
for fast!=nil && fast.Next!=nil{
fast = fast.Next.Next
slow = slow.Next
}
mid := slow.Next
slow.Next = nil
first, second := sortList(head), sortList(mid)
return merge(first, second)
}
func merge(head1 *ListNode, head2 *ListNode) *ListNode {
curHead := &ListNode{}
tmpHead := curHead
for head1 != nil && head2 != nil {
if head1.Val < head2.Val {
curHead.Next = head1
head1 = head1.Next
curHead = curHead.Next
} else {
curHead.Next = head2
head2 = head2.Next
curHead = curHead.Next
}
}
if head1 != nil {
curHead.Next = head1
} else if head2 != nil {
curHead.Next = head2
}
return tmpHead.Next
}