对遇到的经典链表问题思路进行一个总结:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
1、给定一个单链表的结点指针,在O(1)时间内删除这个节结点(非尾结点)
【思路】:确保当前结点不是None, 在此基础上进行后续处理:a)设置一个新结点为当前结点的后一个结点。b)将新设置结点的数据赋值给当前结点。c)当前结点指向新设置结点的next结点
def DeleteNode(pHead, cur):
if cur == None or cur.next == None: # 确保当前结点非None,非尾结点
return
pre = cur.next
cur.val = pre.val
cur.next = pre.next
return pHead
2、给定一个单链表,输出链表的转置链表
链表的转置可以查看这篇文章:https://blog.csdn.net/weixin_39561100/article/details/79818949
3、求链表的倒数第K个节点
【思路】:首先判断链表的长度,判断是否有K个结点。当存在多余K个结点的时候,就用到了链表解决方案中经常使用的方法【运用两个指针,一前一后】。让一个链表先运动K步,然后同时向后运动,当先运动的指针结点为None的时候,后运动的指针对应的链表结点就是所求的倒数第K个结点。
class Solution:
def FindKthToTail(self, head, k):
# write code here
# 第一遍:先计算总共有多少个结点。第二步:两个指针,第一个指针先移动K步,当先移动的指针到达最后时,后移动的指针所指的节点就是所求的结点
if not head:
return head
count = 0
pre = head
while pre:
count += 1
pre = pre.next
if count<k:
return None
pre = head
last = head
for i in range(k):
pre = pre.next
while pre:
pre = pre.next
last = last.next
return last
4、求链表的中间结点。【节点数量为奇数时返回中间结点,偶数时返回中间两个中的任意一个】
【思路】:1)求链表的长度,然后计算中间结点的位置。从头开始运动到中间结点的位置。2)另一种方法同样是运用【两个指针,一快一慢】,一个指针每次运动两步,另一个指针每次运动一步。当快指针指向的结点为None,或者快指针结点的next结点为None时,慢指针指向的结点为中间结点。
def FindMidNode(self, pHead):
if (pHead == None):
return None
fast = slow = pHead
while (fast and fast.next):
fast = fast.next.next
slow = slow.next
return slow
5、判断单链表是否存在环
【思路】:这题还是使用两个指针变量,fast指针每次向前运动两个结点,slow指针每次向前运动一个结点。如果fast指针结点为None,或者fast指针结点的next结点为None,则不存在环。否则由于fast指针运动的快,经过若干圈之后【具体多少圈不确定,和链表的结构有关】,fast和slow会指向的同一结点。
def HasCycle(self, pHead):
"""判断链表是否存在环"""
fast = slow = pHead
while (fast != None and fast.next != None):
fast = fast.next.next
slow = slow.next
if (fast == slow):
return True
return False
6、找到单链表的入口结点【是否有环,有环时求入口结点】
【思路】:可以根据题目5判断是否只存在环;存在环的时候,假设入口结点与初始结点的距离为L1,相遇结点与入口结点的距离为L2。fast结点每一次走两步,slow结点每一次走一步。fast走的路程是slow结点路程的两倍。假设slow运动了n步,我们可以据此写出路程方程组:
L1 + L2 = n
L1 + L2 + K*C = 2*n (K表示fast在赶上slow的过程中多走的环的圈数,C表示环的长度)
由上面的方程可以得出K*C = n,这时候令fast指向pHead结点。然后fast和slow以每次一步的速度运动n次。我们可以知道fast结点刚好运动到相遇的结点,而slow结点运动n步(K*C)之后也是运动到相遇的结点。这一次,fast和slow都是每次一步的速度运动的,所以从入口结点到相遇的结点,fast和slow都会指向同一个结点。即这一次,两个结点第一次相遇的结点为环的入口结点。
def FirstNodeofCycle(self, pHead):
"""find the first node of the cycle of the ListNode"""
if (pHead == None or pHead.next == None):
return None # 一个节点和None都不可能构成环
fast = slow = pHead
while (fast != None and fast.next != None):
fast = fast.next.next
slow = slow.next
if (fast == slow):
break
if (fast != slow): # 链表没有环
return None
fast = pHead # 快指针指向开始结点
while (fast != slow): # 每次向后运动一个结点
fast = fast.next
slow = slow.next
return fast
7、判断两个无环单链表是否相交
【思路】:两个无环单链表如果相交的话,那么从交点开始到最后一个结点都相等。我们可以判断两个链表的最后一个结点是否相等来判断两个无环链表是否相交。
def InterofTheListNode(self, pHead1, pHead2):
# 判断两个无环单链表是否相交
if (pHead1 == None or pHead2 == None):
return False
while (pHead1.next):
pHead1 = pHead1.next
while (pHead2.next):
pHead2 = pHead2.next
if (pHead1 == pHead2):
return True
else:
return False