在有些情况下,存储数据的内存分配不能位于连续的内存块中。 通过指针将其中数据和数据元素的下一个位置的地址都存储起来,这样从当前数据元素的值中就知道下一个数据元素的地址。通常这样的结构被称为指针,而在Python中称为节点。
class Node(object):
def __init__(self, x):
self.data = x
self.next = None
把一系列节点通过链接(next)连接在一起就组成了链表。 根据结构的不同,链表可以分为单向链表、单向循环链表、双向链表、双向循环链表等。下面是链表相关题型的分析和解答。
链表逆序
Reverse Linked List II(翻转列表指定范围)
for循环中的图示:
class Solution(object):
def reverseBetween(self, head, m, n):
dummy = ListNode(0)
dummy.next = head
curr = dummy
for i in range(1, m):
curr = curr.next
tail = curr.next
for i in range(m, n):
if tail is None:
break
tmp = tail.next
tail.next = tmp.next
tmp.next = curr.next # not tail
curr.next = tmp
return dummy.next
Reverse Linked List(翻转整个链表)
while循环中的图示:
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
prev = None
cur = head
while cur:
tmp = cur.next
cur.next = prev
prev = cur
cur = tmp
return prev
求两个链表的交点
Intersection of Two Linked Lists
分别遍历两个链表,得到分别对应的长度。然后求长度的差值,把较长的那个链表向后移动这个差值的个数,然后一一比较即可。
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if not headA or not headB:
return None
countA = countB = 0
currA, currB = headA, headB
while currA:
countA += 1
currA = currA.next
while currB:
countB += 1
currB = currB.next
currA = headA
currB = headB
if countA > countB:
for i in range(countA - countB):
currA = currA.next
elif countB > countA:
for i in range(countB - countA):
currB = currB.next
while currA != currB:
currA = currA.next
currB = currB.next
return currA
成对交换链表的节点
Swap Nodes in Pairs
Given 1->2->3->4, you should return the list as 2->1->4->3.
while循环中的图示:
class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
curr = dummy = ListNode(0)
dummy.next = head
while curr.next and curr.next.next:
node1, node2, node3 = curr.next, curr.next.next, curr.next.next.next
curr.next = node2
node2.next = node1
node1.next = node3
curr = node1
return dummy.next
包含环的链表
Linked List Cycle(是否有环)
只需要设两个指针,一个每次走一步的慢指针和一个每次走两步的快指针,如果链表里有环的话,两个指针最终肯定会相遇。
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head == None or head.next == None:
return False
fast = slow = head
while fast and fast.next:# first fast can avoid AttributeError
fast = fast.next.next
slow = slow.next
if fast is slow:
return True
return False
Linked List Cycle II(求环起始节点)
还是设置两个快慢指针,当两个指针相遇了后,让其中一个指针回到链表起始位置,快慢支针保持同步重新走,此时再相遇的位置就是链表中环的起始位置。
设m为表头到环起始点的距离,n为相遇时走过环起始点的距离,c为环的周长,a为正整数。那么有:
l_fast=m+n+a*c=2*l_slow
l_slow=m+n
=>m+n=a*c
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
fast = slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast is slow:
fast = head
while fast is not slow:
fast = fast.next
slow = slow.next
return fast
return None
链表划分
Partition List
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
解法一:首先找到第一个大于或等于给定值的节点(4),然后再找小于给定值的节点,每找到一个就将其取出置于4之前即可。
解法二:将所有小于给定值的节点取出组成一个新的链表,此时原链表中剩余的节点的值都大于或等于给定值,只要将原链表直接接在新链表后即可。下面是解法二的实现:
def partition(self, head, x):
h1 = l1 = ListNode(0)
h2 = l2 = ListNode(0)
while head:
if head.val < x:
l1.next = head
l1 = l1.next
else:
l2.next = head
l2 = l2.next
head = head.next
l2.next = None
l1.next = h2.next
return h1.next
复杂的链表复制
Copy List with Random Pointer
# Definition for singly-linked list with a random pointer.
# class RandomListNode(object):
# def __init__(self, x):
# self.label = x
# self.next = None
# self.random = None
分三步进行:
1. 在原链表的每个节点后面拷贝出一个新的节点
2. 依次给新的节点的随机指针赋值:cur.next.random = cur.random.next
3. 断开链表可得到深度拷贝后的新链表
class Solution(object):
def copyRandomList(self, head):
"""
:type head: RandomListNode
:rtype: RandomListNode
"""
# copy and combine copied list with original list
cur = head
while cur:
copy = RandomListNode(cur.label)
copy.next = cur.next
cur.next = copy
cur = copy.next
# update random node in copied list
cur = head
while cur:
if cur.random:
cur.next.random = cur.random.next
cur = cur.next.next
# split copied list from combined one
dummy = RandomListNode(0)
cur, copy_cur = head, dummy
while cur:
copy_cur.next = cur.next
cur.next = cur.next.next
copy_cur, cur = copy_cur.next, cur.next
return dummy.next
合并链表(2个与多个)
Merge Two Sorted Lists
新建一个链表,然后比较两个链表中的元素值,把较小的那个链到新链表中,由于两个输入链表的长度可能不同,所以最终会有一个链表先完成插入所有元素,则直接另一个未完成的链表直接链入新链表的末尾。
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
init = out = ListNode(0)
while l1 and l2:
if l1.val < l2.val:
out.next = l1
l1 = l1.next
else:
out.next = l2
l2 = l2.next
out = out.next
out.next = l1 or l2
return init.next
Merge k Sorted Lists
解法一:利用mergeTwoLists进行两两合并。
解法二:把k个链表放入列表中排序,依次取出组成新的链表
class Solution(object):
def mergeKLists(self, lists):
def mergeTwoLists(L1,L2):
pass
if not lists:
return None
left, right = 0, len(lists)-1
while right > 0:
if left >= right:
left = 0
else:
list[left] = mergeTwoLists(list[left],list[right])
left += 1
right -= 1
return lists[0]
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
values=[]
for list1 in lists:
while list1:
values.append(list1.val)
list1=list1.next
values.sort()
result=head=ListNode('')
for i in values:
head.next=ListNode(i)
head=head.next
return result.next