链表的中间结点

算法分析:使用快慢指针slow 和fast
- 情况一
- 情况二

代码:
func middleNode(head *ListNode) *ListNode {
fast := head
slow := head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
return slow
}
环形链表

- 快指针一次走两步,慢指针一次走一步,如果链表有环,那么两个指针始终会相遇。
时间复杂度 O(n),空间复杂度 O(1)
func hasCycle(head *ListNode) bool {
slow := head
fast := head
for fast != nil && fast.Next != nil {
slow = slow.Next //慢指针走一步
fast = fast.Next.Next //快指针走两步
if slow == fast { //慢指针和快指针相等说明有环
return true
}
}
return false
}
- hash表将遍历过的节点记录下来,如果又遍历到了,表示链表有环,时间复杂度O(n),空间复杂度O(n)
func hasCycle(head *ListNode) bool { // hash表
hash := make(map[*ListNode]int) // 开一个哈希表记录该节点是否已经遍历过,值记录节点索引
for head != nil {
if _,ok := hash[head]; ok { // 该节点遍历过,形成了环
return true
}
hash[head] = head.Val // 记录该节点已经遍历过
head = head.Next
}
return false
}
删除链表的倒数第n个结点

- 使用快慢指针,fast先走n步,这样控制fast和slow之间第距离是n,等fast走完,n的位置就是倒数第n个结点,因为使用了头结点所以slow的位置为倒数第n+1个结点。
方法一:
func removeNthFromEnd(head *ListNode, n int) *ListNode {
if head.Next == nil {
return nil
}
headNode := new(ListNode)
headNode.Next = head
slow := headNode
fast := headNode
for i:=0; i < n; i ++ {
fast = fast.Next
}
for fast.Next != nil {
slow = slow.Next
fast = fast.Next
}
slow.Next = slow.Next.Next
return headNode.Next
}
方法二:
func removeNthFromEnd(head *ListNode, n int) *ListNode {
headNode := new(ListNode)
headNode.Next = head
slow := headNode
fast := headNode
temp := n
for ; fast.Next!=nil; temp-- {
if(temp<=0){ //control
slow=slow.Next;
}
fast=fast.Next;
}
slow.Next = slow.Next.Next
return headNode.Next
}