1. 将含有random指针的链表复制一份
第一遍循环:将每个节点复制一份放在原节点后面;
第二遍循环:每个新复制节点的random指向的是“其对应原节点的random节点的下一个节点”,如此得到一个double的大链表;
第三遍循环:将大链表拆成两份。
class Solution:
# 返回 RandomListNode
def Clone(self,pHead):
# write code here
if pHead is None:
return pHead
#第一遍循环复制指针
t1 = pHead
while t1:
temp = RandomListNode(t1.label)
temp.next = t1.next
t1.next = temp
t1 = temp.next
#第二遍复制random指针
t1 = pHead
while t1:
t2 = t1.next
if t1.random:
t2.random = t1.random.next
t1 = t2.next
#拆分成两个链表
h1 = pHead
h2 = pHead.next
t1 = h1
t2 = h2
while t1:
if t1.next.next:
t1.next = t1.next.next
t2.next = t2.next.next
else:
t1.next = None
t2.next = None
t1 = t1.next
t2 = t2.next
return h2
2. 判断链表是否有环
无环返回-1,有环,返回环的第一个节点的值。
方法一:使用哈希表,若走完链表无重复值则无环,否则第一个重复的值为环的入口。空间复杂度O(n);
方法二:使用快慢指针,快指针走两步,慢指针走一步。若快指针走到None,说明无环。否则当快慢指针第一次相遇时,快指针回到头结点,然后快慢指针同时向后走一步,知道两者再次相遇,该相遇点为环的入口。空间复杂度O(1)。
class ChkLoop:
def chkLoop(self, head, adjust):
if head is None:
return -1
f = head
s = head
#1.若快指针走到none,说明无环;2. 快慢指针相遇后,快从头以步长1走,慢继续走,下一次相遇点为环的第一个入节点
while 1:
#s走一步,f走两步
if f is None or f.next is None:
return -1
s = s.next
f = f.next.next
#如果s与f相遇,出循环
if s == f:
break
#第二次循环,s继续原位置走一步,f从头走一步知道相遇
f = head
while 1:
if s == f:
return s.val
s = s.next
f = f.next
3. 判断两个无环链表相交
方法一:哈希表,遍历链表1并将每个node放入哈希表,然后遍历链表2,若发现重复节点,则该节点为相交节点。若链表2遍历完了都没有发现重复节点,则不相交。空间复杂度O(n)。
方法二:遍历链表1,记录长度M;遍历链表2,记录长度N;先遍历长的链表知道二者长度相等,再同时遍历,若有相同节点,则返回。否则不相交。空间复杂度O(1), 时间复杂度O(m+n)
#方法二
class CheckIntersect:
def chkIntersect(self, headA, headB):
# write code here
if headA is None or headB is None:
return False
#计算两个链表的长度
h1 = headA
num1 = 0
h2 = headB
num2 = 0
while h1:
h1 = h1.next
num1 += 1
while h2:
h2 = h2.next
num2 += 1
#先遍历长链表
if num1 > num2:
h1 = headA
for i in range(num1-num2):
h1 = h1.next
h2 = headB
else:
h2 = headB
for i in range(num2-num1):
h2 = h2.next
h1 = headA
#此时同时移动h1和h2,看是否有相等节点
while h1:
if h1 == h2:
return True
h1 = h1.next
h2 = h2.next
return False
4. 判断两个有环链表是否相交
分别找到两个的第一个入环节点(方法如第2题)node1和node2,若node1==node2, 则肯定相交,相交点在node1之前,可以根据第3题来找到相交点。若node1 != node2, 则node1往下走,在返回自己之前若与node2相遇,则相交,否则不相交。
class ChkIntersection:
def chkInter(self, head1, head2, adjust0, adjust1):
#找到两个链表第一个入环节点
node1 = self.findFirstNode(head1)
node2 = self.findFirstNode(head2)
#如果两个入环节点相等,则说明相交的位置在入环之前,则肯定相交,返回True
if node1 == node2:
return True
#如果两个入环节点不相等,让链表1的入环节点往下走,如果在遇到自己之前能遇到链表2的入环节点,则相交。
h1 = node1.next
while 1:
if h1 == node2:
return True
if h1 == node1:
break
h1 = h1.next
return False
def findFirstNode(self, head):
f = head
s = head
while 1:
f = f.next.next
s = s.next
if f == s:
break
f = head
while 1:
if f == s:
return f
f = f.next
s = s.next
5. 判断两个链表是否相交(不知道有没有环)
综合2,3,4三道题:
1)若两个有环:判断有环链表是否相交;
2)若两个无环:判断无环链表是否相交;
3)一个有环一个无环:一定不相交;
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#1. 一个有环,一个无环,不相交
#2. 两个无环,判断
#3. 两个有环,判断
class ChkIntersection:
def chkInter(self, head1, head2, adjust0, adjust1):
node1 = self.checkCircle(head1)
node2 = self.checkCircle(head2)
#若都有环,则判断两个有环链表是否相交
if node1 and node2:
if node1 == node2:
return True
p = node1.next
while 1:
if p == node2:
return True
if p == node1:
break
p = p.next
return False
#若都无环,则判断两个无环链表是否相交:
if not node1 and not node2:
h1 = head1
h2 = head2
num1 = 0
num2 = 1
while h1:
h1 = h1.next
num1 += 1
while h2:
h2 = h2.next
num2 += 1
if num1 > num2:
h1 = head1
for i in range(num1-num2):
h1 = h1.next
h2 = head2
else:
h2 = head2
for i in range(num2-num1):
h2 = h2.next
h1 = head1
while h1:
if h1 == h2:
return True
h1 = h1.next
h2 = h2.next
return False
#若一个有环一个无环,肯定不相交,返回false
else:
return False
#若有环,返回第一个入环节点。若无环,返回false。
def checkCircle(self, head):
f = head
s = head
while 1:
if f is None or f.next is None:
return False
f = f.next.next
s = s.next
if f == s:
break
f = head
while 1:
if f == s:
return f
f = f.next
s = s.next
总结:
trick1:在无空间复杂度要求的情况下,可以使用哈希表简化计算;
trick2:快指针走两步,慢指针走一步,第一次相交;快指针回到头走一步,慢指针走一步,第二次相交点为环的入点;
trick3:同时遍历两个链表看是否有相同节点时,先比较,后移动。
总之只要把第5题做会就OK了。