leetcode刷题 day8 | 链表:删除倒数第N个节点+链表相交+环形链表

知识点


题目


  1. 删除链表的倒数第N个结点
  • 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
  • 示例:
    在这里插入图片描述
    输入:head = [1,2,3,4,5], n = 2
    输出:[1,2,3,5]
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy_head=ListNode()
        dummy_head.next=head

        fast_node,slow_node=dummy_head,dummy_head

        while(n+1):
            fast_node=fast_node.next
            n-=1
        while(fast_node):
            slow_node=slow_node.next
            fast_node=fast_node.next

        slow_node.next=slow_node.next.next

        return dummy_head.next
        

注释:
为什么不用while(fast_node.next)是因为仅有一个结点时需要单独判断。

  1. 链表相交
  • 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
  • 示例:
    图示两个链表在节点 c1 开始相交:
    在这里插入图片描述
    解法①:
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if headA==None or headB==None:
            return None
        
        curA,curB=headA,headB
        while(curA !=curB):
            curA=curA.next if curA else headB
            curB=curB.next if curB else headA
        
        return curA    

证明:

考虑两种情况,第一种情况是两个链表相交,第二种情况是两个链表不相交。
情况一:两个链表相交
链表 headA 和 headB 长度分别是 m 和 n 。假设链表 headA 的不相交部分有 a 个节点,链表 headB 的不相交部分有 b 个节点,两个链表相交的部分有 c 个节点,则有 a+c=m,b+c=n。
如果 a=b,则两个指针会同时到达两个链表相交的节点,此时返回相交的节点;
如果 a ≠b,则指针 pA 会遍历完链表 headA,指针 pB 会遍历完链表 headB,两个指针不会同时到达链表的尾节点,然后指针 pA 移到链表 headB 的头节点,指针 pB 移到链表 headA 的头节点,然后两个指针继续移动,在指针 pA 移动了 a+c+b 次、指针 pB 移动了 b+c+a 次之后,两个指针会同时到达两个链表相交的节点,该节点也是两个指针第一次同时指向的节点,此时返回相交的节点。
情况二:两个链表不相交
链表 headA 和 headB 的长度分别是 m 和 n。考虑当 m=n 和 m ≠ m 时,两个指针分别会如何移动:
如果 m=n,则两个指针会同时到达两个链表的尾节点,然后同时变成空值 null,此时返回 null;
如果 m ≠ n,则由于两个链表没有公共节点,两个指针也不会同时到达两个链表的尾节点,因此两个指针都会遍历完两个链表,在指针 pA 移动了 m+n 次、指针 pB 移动了 n+m 次之后,两个指针会同时变成空值 null,此时返回 null。

解法②

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        lenA,lenB=0,0
        curAA,curBB=headA,headB
        #计算链表长度
        while(curAA):
            lenA+=1
            curAA=curAA.next
        while(curBB):
            lenB+=1
            curBB=curBB.next
        #计算链表长度差
        distance=abs(lenA-lenB)
        curA=headA
        curB=headB
        #尾部对齐链表,并比较
        if lenA>lenB:
            while(distance):
                curA=curA.next
                distance-=1
            while(curA):
                if curA==curB:
                    return curA
                curA=curA.next
                curB=curB.next
            return curA
        else:
            while(distance):
                curB=curB.next
                distance-=1
            while(curB):
                if curA==curB:
                    return curB
                curA=curA.next
                curB=curB.next             
            return curB      
  1. 环形链表 II
  • 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
    如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
    不允许修改 链表。
  • 示例:
    在这里插入图片描述
    输入:head = [3,2,0,-4], pos = 1
    输出:返回索引为 1 的链表节点
    解释:链表中有一个环,其尾部连接到第二个节点。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        fast=head
        slow=head
        while(fast and fast.next):
            fast=fast.next.next
            slow=slow.next
            if fast==slow:
                index1=fast
                index2=head
                while(index1!=index2):
                    index1=index1.next
                    index2=index2.next
                return index1

        return None

讲解:
代码随想录:环形链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值