LeetCode 206
本题是一道非常基础的反转单链表。首先想到的方法是把链表转换成数组直接逆序,这里不再细说。另外两种方法是递归和迭代。递归方法是指先反转最后两个节点,依次往前至全部反转。迭代法是从左至右反转。
class Solution:
def reverseList(self, head): # 递归法
if head is None or head.next is None:
return head
else:
dummy = self.reverseList(head.next)
head.next.next = head
head.next = None
return dummy
def reverseList2(self, head): # 迭代法
prev = None
while head:
# head.next, prev, head = prev, head, head.next 由于Python的特性,下面四行代码可写为一行
curr = head
head = head.next
curr.next = prev
prev = curr
return prev
LeetCode 142
本题判断一个链表是否有环,有环的话返回环的起始节点。本题使用快慢指针寻找环,也就是以前博文提到过的Floyd判圈算法。找到后怎样寻找起始节点呢?我们做一段证明。设链表头到环入口的距离为l1,入口到两指针相遇的距离为l2,c是环的长度,n为快指针在环中的遍历次数。当慢指针和快指针相遇时,慢指针走了l1 + l2的距离,快指针走了l1 + l2 + n * c的距离。而快指针走的步数是慢指针的两倍,所以可得2* (l1 + l2) = l1 + l2 + n * c ,整理后得l1 = (n - 1) * c + (c - l2)。令n等于1,可得l1 = c - l2。也就是说,链表头到环入口的距离和相遇距离到环入口的距离相等。在找到相遇节点后,头节点和慢/快指针同步走下去,相遇时即为环入口。
class Solution(object):
def detectCycle(self, head):
slow = fast = head
while fast and fast.next:
slow, fast = slow.next, fast.next.next
if slow == fast:
break
else:
return None
while head != slow:
head, slow = head.next, slow.next
return head
LeetCode 148
链接:Sort List
本题为链表排序,使用归并排序解决,基本思路是:找到链表的中间节点,然后递归对前半部分和后半部分分别进行归并排序,最后合并两个有序链表。找中间节点需要使用快慢指针。快指针走的步数是慢指针的两倍,当快指针走到链表结尾时,慢指针正好走到中央。合并链表部分记录了迭代法和递归法两种链表合并方法。
class Solution(object):
def sortList(self, head):
if not head or not head.next:
return head
pre = None
slow = fast = head
while fast and fast.next:
pre, slow, fast = slow, slow.next, fast.next.next
pre.next = None # 截断链表左半部分
return self.merge(self.sortList(head), self.sortList(slow))
def merge(self, h1, h2): # 迭代法
dummy = tail = ListNode(None)
while h1 and h2:
if h1.val < h2.val:
tail.next, h1 = h1, h1.next
else:
tail.next, h2 = h2, h2.next
tail = tail.next
tail.next = h1 or h2
return dummy.next
def merge2(self, l1, l2): # 递归法
if not l1 or not l2:
return l1 or l2
if l1.val < l2.val:
l1.next = self.merge2(l1.next, l2)
return l1
else:
l2.next = self.merge2(l1, l2.next)
return l2
参考资料: 经典算法——单链表反转的递归方法和非递归方法 leetcode题解 problem 142 Linked List Cycle II