链表(2)快慢指针

169 阅读1分钟

链表的中间结点

算法分析:使用快慢指针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 {    // hashhash := 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
}