一、判断链表是否有环
1、问题描述
给定一个链表,判断其是否有环
2、思路
两个方法:
- 借助哈希表
- 不借助hash表
3、python实现
方法一:
- 遍历链表得到节点
- 判断该节点是否是哈希表中的某一个key,若不是则加入,若是则返回即为第一个有环的节点
- 若遍历到最后遇到None,则不存在环
'''
问题一:判断链表是否有环
'''
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
'''
方法一:借助hash表,python中对应的就是字典
'''
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head is None:
return 0
tmp_dict = {}
p = head
while p is not None:
if tmp_dict.has_key(p):
return 1
else:
tmp_dict[p] = 1
p =p.next
return 0
方法二:
- 引入一个快指针,一次走两步;一个慢指针,一次走一步
- 遍历链表,当慢指针与快指针相等时,则说明有环。否则若快指针为None时无环
- 当快指针与慢指针相等时,快指针回到头指针head,然后快指针由原来的一次两步变成一次一步,快指针与慢指针一定会在第一个入环节点处相遇
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head is None or head.next is None or head.next.next is None:
'''
这里还是那个问题,就是链表中next的next要写在next的后面,因为是顺序结构运行
可能在next的时候就已经是none了,这时候就会报错了
'''
return 0
fast = head.next.next
slow = head.next
while fast != slow:
if fast.next == None or fast.next.next == None:
'''
这里是对奇数和偶数都做了判断,同样要遵循先next,再next的next原则
'''
return 0
slow = slow.next
fast = fast.next.next
return 1
# fast = head #这几行是如果需求是返回有环的第一个节点,那么就是这几行即可
# while fast != slow:
# fast = fast.next
# slow = slow.next
#
# return fast
二、返回两个无环链表相交的第一个节点
1、思路
两个方法:
- 借助hash表
- 不借助hash表
2、python实现
方法一:
- 遍历head1链表,将链表存入hash表中
- 遍历head2链表,每取出一个都在hash表判断是否含有,若含有则返回。即为第一个交点
- 若head2到None也未在hash表中找到,则无交点
'''
问题二:如何返回两个无环链表相交时的第一个节点
'''
'''
方法一:
借助辅助空间,hash表
'''
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
dict_node = {}
pA = headA
while pA is not None:
dict_node[pA] = 1
pA = pA.next
pB = headB
while pB != None:
if dict_node.has_key(pB):
return pB
pB = pB.next
return None
'''
方法二、
- 遍历head1和head2,记录head1和head2的长度与尾指针end1,end2
- 判断end1和end2是否相等。若不想等,则不可能相交
- 比较两个长度length1和length2,假设length1为100,length2为80,则让head1先走20步,然后head1和head2一起走。它俩一定会走到相交的第一个节点处。
'''
方法二:不借助hash表,
'''
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if headA is None or headB is None:
return None
pA = headA
pB = headB
n = 0
while pA is not None:
n += 1
if pA.next is None:
endA = pA
pA = pA.next
while pB is not None:
n -= 1
if pB.next is None:
endB = pB
pB = pB.next #记录两个链表的长度,还有两个链表的尾结点;这里用一个n记录二者的差值;相比于记录两个链表的长度,这样省去了一个变量,
if endA != endB:
return None
pA = headA
pB = headB
while abs(n) != 0:
if n > 0:
pA = pA.next
n -= 1
else:
pB = pB.next
n += 1 #这里可以用一个“三目运算符”实现
while pA != pB:
pA = pA.next
pB = pB.next
return pA
三、返回两个有环链表中相交时的第一个节点
1、思路
三种拓扑形态,分类讨论
2、python实现
'''
问题三:如何返回两个有环链表中相交时的第一个节点
'''
def bothLoop(headA, headB, loopA, loopB):
'''
三种拓扑结构,分类讨论
'''
if headA is None or headB is None:
return None
if loopA == loopB:
'''
对应第二种拓扑结构
'''
pA = headA
pB = headB
n = 0
while pA is not None:
n += 1
if pA.next is None:
endA = pA
pA = pA.next
while pB is not None:
n -= 1
if pB.next is None:
endB = pB
pB = pB.next #记录两个链表的长度,还有两个链表的尾结点;这里用一个n记录二者的差值;相比于记录两个链表的长度,这样省去了一个变量,
if endA != endB:
return None
pA = headA
pB = headB
while abs(n) != 0:
if n > 0:
pA = pA.next
n -= 1
else:
pB = pB.next
n += 1 #这里可以用一个“三目运算符”实现
while pA != pB:
pA = pA.next
pB = pB.next
return pA
#对应拓扑一结构或者拓扑三结构
else:
pA = loopA
while pA.next != loopA:
if pA == loopB:
return loopA #对应拓扑三结构
pA = pA.next
return None #对应拓扑一结构