今天还是链表专题,相对于昨天链表的ood题,今天的逻辑相对清晰.
24. 两两交换链表中的节点 ,
这道题充分说明了做dummy node的重要性.如果不做,就要非常详细的具体情况讨论,如果做了则会事半功倍. 还有一个迷惑的点在于要移动三个指针并不是两个.如果以两个为一组的话,这道题还涉及到了组与组之前的联系关系,需要移动指针
Way1:
基本思路很明确,定义三个指针即pre,cur, 和pos. 每次循环(判断pre.next and pre.next.next是否存在) 都要进行指针cur和pos的指针互换,同时最后不要忘记pre.next也要发生变动.在这之后移动pre进行下次循环
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy=ListNode()
dummy.next=head
pre=dummy
while pre.next and pre.next.next:
cur=pre.next
pos=pre.next.next
cur.next=pos.next
pos.next=cur
pre.next=pos
pre=pre.next.next
return dummy.next
19.删除链表的倒数第N个节点
这道题其实有两种吧方法去做,各有优略
Way1:
这种方式比较简单粗暴,基本思路就是先算出一共有多少个node,然后移动size-n-1词,然后改变next即可
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
cur=head
size=0
while cur:
cur=cur.next
size+=1
if size==n:
return head.next
cur=head
for _ in range(size-n-1):
cur=cur.next
cur.next=cur.next.next
return head
Way2:
使用two pointer的方法.通过fast先移动n次然后以fast作为铆钉,去移动slow直到fast为空,这样的话就凭空创造了找到了倒数第n+1的node
dummy=ListNode()
dummy.next=head
fast=dummy
slow=dummy
for _ in range(n+1):
fast=fast.next
while fast:
fast=fast.next
slow=slow.next
slow.next=slow.next.next
return dummy.next
160. 链表相交
这道题也是比较灵活的题,方法上看是否要借助array或者set来记录值
Way1:
相对来说简单暴力,遍历A的过程中记录所有的值,然后遍历B的过程中去找第一个在A中的值
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
one = headA
xs=set()
while one:
xs.add(one)
one=one.next
two = headB
while two:
if two in xs:
return two
two=two.next
return None
Way2:
这种方法就要考虑的很多了.首先要判断是什么时候相交可能出现: 很明显相交是在较长的字符串的第lena-lenb的地方开始的,在这之后只要移动两个list的指针并且每次判断是否相等即可
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
lena,lenb=0,0
cur=headA
while cur:
lena+=1
cur=cur.next
cur=headB
while cur:
lenb+=1
cur=cur.next
cura,curb=headA,headB
if lena > lenb:
curb,cura=cura,curb
lena,lenb=lenb,lena
for _ in range(lenb-lena):
curb=curb.next
while cura:
if cura==curb:
return cura
cura=cura.next
curb=curb.next
return None
142.环形链表II
这道题没有什么捷径,首先要进行数学分析,通过分析路径我们得知 x=(n-1)(y+z)+z, 然后即可确定方法,
Way1:
先利用快慢指针确定环,然后再重置slow=head去寻找环的起始位置
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow=head
fast=head
while fast and fast.next:
slow=slow.next
fast=fast.next.next
if slow==fast:
break
if not fast or not fast.next:
return None
slow=head
while slow!=fast:
slow=slow.next
fast=fast.next
return fast
链表专题总结:
从方法上来说two pointer是最常见的. 一些小的tips是非常重要的,比如建立dummy node,比如进行数学路径分析.这些tips不仅能够简化需要考虑的情况,而且可以帮助确定方法.除此之外, 链表的node的数量是非常重要的,一般来说遇到链表题,首先先求个node的总数.这和array一般先做个排序是异曲同工之妙的.