LeetCode 链表题目经典解法 —— 快慢指针

334 阅读2分钟

快慢指针方法也被称为 Hare & Tortoise 算法,该算法会使用两个在数组(或序列/链表)中以不同速度移动的指针。

61. 旋转链表

leetcode-cn.com/problems/ro…

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

题解

本题可以使用快慢指针的方法,首先快指针向后移动k个节点。

然后快,慢指针一同向后前进,直到快指针到达最后一个节点。

此时,慢指针的下一个节点,就是倒数第K个节点。

这时,快指针指向头节点,进行闭环,慢指针的下一个节点置为nil。

Untitled Diagram (4).png

func rotateRight(head *ListNode, k int) *ListNode {
   if head == nil || head.Next == nil || k == 0 {
      return head
   }
   l := getLen(head)
   k = k % l //整除取余,取最少步数

   slow := head
   fast := head

   //快指针先向后移动k
   for i := 0; i < l; i++ {
      fast = fast.Next
   }

   //快慢指针同时向后
   for fast.Next != nil {
      fast = fast.Next
      slow = slow.Next
   }

   //切换节点指向
   fast.Next = head
   head = slow.Next
   slow.Next = nil
   return head
}

//获取链表长度
func getLen(head *ListNode) int {
   var l int
   for head != nil {
      head = head.Next
      l++
   }
   return l
}

109. 有序链表转换二叉搜索树

leetcode-cn.com/problems/co…

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

题解

快慢指针是寻找链表中点的好办法。快指针的速度是慢指针的两倍。

当快指针到末尾节点的时候,慢指针就是此链表的中点。

此题目利用,寻找有序链表的中点,作为二叉树的一个节点,左右子树通过递归生成。

Untitled Diagram (5).png

func sortedListToBST(head *ListNode) *TreeNode {
   return buildTree(head, nil)
}

func buildTree(left, right *ListNode) *TreeNode {
   if left == right {
      return nil
   }

   //获取有序链表的中点
   mid := getMid(left, right)
   //中点即为该层递归二叉树的节点
   root := &TreeNode{mid.Val, nil, nil}
   //递归生成二叉树
   root.Left = buildTree(left, mid)
   root.Right = buildTree(mid.Next, right)
   return root
}

func getMid(left, right *ListNode) *ListNode {
   slow := left
   fast := left
   for fast != right && fast.Next != right {
      fast = fast.Next.Next
      slow = slow.Next
   }
   return slow
}

141. 环形链表

leetcode-cn.com/problems/li…

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

题解

快慢指针,快指针的速度是慢指针的两倍。

如果链表有环,那么快指针如果入环,那么当慢指针也入环,那么快指针迟早会追上慢指针。

func hasCycle(head *ListNode) bool {
   fast, slow := head, head
   for fast != nil && fast.Next != nil {
      fast = fast.Next.Next
      slow = slow.Next
      if fast == slow {
         return true
      }
   }
   return false
}