都是一些LeetCode上关于链表的题目,多刷一些这样的题目有助于我们全面熟悉链表那一套理论方法。
题目1. 61. Rotate List (将链表右移K个位置)
Given a list, rotate the list to the right by k places, where k is non-negative.
Example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.
题目解析:
找倒数第k个结点类似,先获取长度最关键,要注意对k>=长度的处理。关键点在于利用三个结点:head(链表头),p(链表尾),q(倒数第k结点的前一个),将三者按顺序连起来即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def rotateRight(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if head == None:
return None
length = 1
p = head
while p.next:
p = p.next
length += 1
if k == length:
return head
elif k > length:
k = k%length
cn = 1
q = head
while cn < (length-k):
q = q.next
cn += 1
p.next = head
newhead = q.next
q.next = None
return newhead
题目2. 86. Partition List(链表分割)
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.You should preserve the original relative order of the nodes in each of the two partitions.
For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
题目解析:
很难想到这题正确的解题思路,开始想象着找到分割的位置,然后将分割点两侧不应在这一组的结点"交换"。错就错在交换了,首先,链表的结点交换是操作中最复杂的操作,详细的可见鄙人所做的py的链表实现;其次,交换破坏了原始相对位置。这一思路可以改良为,将分割点左侧大于等于x的结点插入到分割点右侧(依次),将右侧小于x的插入到分割点左侧(这一步实现可能比较费劲)。
于是看了他人的思路,代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def partition(self, head, x):
"""
:type head: ListNode
:type x: int
:rtype: ListNode
"""
if head == None:
return head
p1 = ListNode(-1)
p2 = ListNode(-1)
h1, h2 = p1, p2
while head:
if head.val <x:
p1.next = head
p1 = p1.next
else:
p2.next = head
p2 = p2.next
head = head.next
p2.next = None
p1.next = h2.next
return h1.next
申请两个头指针,只遍历一遍链表,将两类结点各自挑出来依次连接,最后再合并,实在是简洁高效!时间复杂度O(n),空间复杂度O(1)。还是要领会这一思想。
思考:这一问题实际上说明,快速排序对于单链表存储结构仍然适用,所给的x其实是快排中的主元。(不懂快排的可自行学习,或者等待鄙人慢慢更新博客0 0)
题目3. 92. Reverse Linked List II(链表逆序)
Reverse a linked list from position m to n. Do it in-place and in one-pass.
For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,
return 1->4->3->2->5->NULL.
Note: Given m, n satisfy the following condition: 1 ≤ m ≤ n ≤ length of list.
题目解析:
这是链表逆转操作的加强版,在基本功的逆序操作的基础上,将逆转后的链表头尾再连接到应该连接的地方。代码如下:
class Solution:
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
:type m: int
:type n: int
:rtype: ListNode
"""
if head == None:
return head
elif m == n:
return head
new = ListNode(-1)
new.next = head
head = new
p = head
pre = head
for i in range(m):
pre = p
p = p.next
q = p
for i in range(n-m):
q = q.next
# reverse
pre_p = q.next
cur = p
for i in range(n-m+1):
h = cur
tmp = cur.next
cur.next = pre_p
pre_p = cur
cur = tmp
pre.next = q
return head.next
注意的地方有:1,当m=1时比较麻烦,所以一般涉及到链表头的改变的问题,可以在头部之前建一结点,这样可将问题一般化处理;2,特殊情况还有m=n时;3,注意这几个结点的作用,pre 是m点之前的点,p(cur)是m点,q是n点,pre_p即q.next是m-n逆转后尾部需要连接的地方(在其他的逆转问题中一般用None)