代码随想录训练营打卡第四天|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,142.环形链表II,面试题 02.07. 链表相交

链表|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,142.环形链表II,面试题 02.07. 链表相交

文档链接:代码随想录
做题感悟:

  • 两两交换链表中的节点,巧妙的地方在于:虚拟头节点(头节点一般化)、只需要判断尾部是余0节点还是1节点(保证节点访问不溢出,先判断cur.next,再判断cur.next.next.)节点交换的结构固定,为头->节点1->节点2->尾,简化思维。
  • 删除链表的倒数第n个节点:设定快慢指针保证快指针比慢指针快n+1步,当快指针访问到链表最后时,慢指针恰好指向目标节点的前一个节点。
  • 环形链表:先利用快慢指针确定是否有环,再结合x、z之间的运算关系,得知起点和快慢指针相遇点出发的指针一定会在入口处相遇,进而得到入口指针。
  • 链表相交:先算链表长度,将长短不一的链表拉齐,随后遍历链表,直到遍历的指针相等,即为相交点。

题目一:24. 两两交换链表中的节点——15:00-15:44=44min

题目链接:题目
文档链接:文档
视频讲解:视频

代码随想录训练营打卡第四天|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,142.环形链表II,面试题 02.07. 链表相交_第1张图片

  • 在进行两个节点进行交换时,设计一个如下的结构:
    代码随想录训练营打卡第四天|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,142.环形链表II,面试题 02.07. 链表相交_第2张图片
  • 在两节点前存在一个cur节点用于衔接(因此为了将头节点一般化,可以设置虚拟头节点)
  • 其中,链表长度偶数和奇数情况下,终止的条件不同,若最后移动的cur.next为None,则链表为偶数,如果cur.next.next为None,则链表长度为奇数。
  • 先判断cur.next不为None,才能进一步判断,cur.next.next
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummyhead=ListNode(next=head)#定义虚拟头节点、一般化头节点
        #ListNode不是类里的函数,不需要使用slef,调用类中定义的函数和变量才需要self
        cur=dummyhead
        while cur.next != None and cur.next.next != None:
        # 先判断cur.next是不是空,才能进一步确定cur.next.next是不是空可以防止越界
        # 链表长度为偶数,则cur.next为空
        # 链表长度为奇数,则cur.next.next为空
            temp1 = cur.next
            temp3 = cur.next.next.next
            cur.next=cur.next.next
            cur.next.next=temp1
            temp1.next=temp3
            cur=cur.next.next # 将cur移动到新的需要两两交换的节点的前一个节点
        return dummyhead.next

题目二:19.删除链表的倒数第N个节点——16:00-16:43=43min

题目链接:题目
文档链接:文档
视频讲解:视频

代码随想录训练营打卡第四天|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,142.环形链表II,面试题 02.07. 链表相交_第3张图片

  • 首先N!= 0
  • 设定快慢指针,保证快指针比慢指针快n + 1
  • 出现fast = fast.next情况下,要先判断fast是不是None
# 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]:
        # 难道不需要考虑链表为空的情况吗?这里没有交代,因此不需要考虑
        # 定义一个快指针、慢指针,当快慢指针之间相差n+1,当快指针指向空,慢指针正好指向
        dummyHead = ListNode(next = head)
        fast = dummyHead
        slow = dummyHead
        n += 1
        while n and fast != None:# 先移动fast保证fast先于slow指针n+1
            n -= 1
            fast=fast.next # 一般有这句话都需要确保fast不为None
        
        while fast != None:
            fast=fast.next
            slow=slow.next # fast不是None,slow一定不是
        
        slow.next=slow.next.next # 由于fast至少比slow快2个节点,因此当fast == None时,slow一定不会访问越界

题目三:环形链表——17:23-18:33=70min

题目链接:添加链接描述
文档链接:文档在这里插入图片描述

视频讲解:视频代码随想录训练营打卡第四天|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,142.环形链表II,面试题 02.07. 链表相交_第4张图片

  • 先利用快慢指针判断相遇的位置

  • 标记相遇的位置,利用相遇位置z、y、x之间的相对关系

  • 可以确定,当起点出发的指针和x出发的指针一定会在入口处相遇,进而确定入口的位置。

  • 一会再推一遍

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        fast=head
        slow=head
        # 先利用快慢指针判断有没有环。
        while fast != None and fast.next != None:
            fast = fast.next.next # 一次移动两格
            slow = slow.next # 一次移动一格
            if slow == fast:
                index1 = fast # 确定z的位置
                index2 = head 
                while index1 != index2: # 分别从两头出发,相遇处即为入口处。
                    index1=index1.next
                    index2=index2.next
                return index1
        return None

题目四:面试题 02.07. 链表相交 ——18:40-19:10=30min

题目链接:题目
文档链接:文档
视频讲解:无
代码随想录训练营打卡第四天|24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,142.环形链表II,面试题 02.07. 链表相交_第5张图片

  • 难度不大,首先先计算链表长度,确定两个链表之间的差距
  • 其次,在头端把两段链表拉齐
  • 同时遍历拉齐后的链表,直到访问节点相等
class Solution:
    def Linksize(self,head: ListNode) -> int:
        temp=head
        size=0
        while temp:
            temp=temp.next
            size += 1
        return size
        
    def Headmove(self,head: ListNode,dis: int) -> ListNode:
        temp=head
        while dis:
            temp=temp.next
            dis -= 1
        return temp

    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if headA == None or headB == None:
            return None
        #先计算链表长度
        #把两条链表拉齐
        #移动指针判断指针是否相等,如果相等就相交。
        
        sizeA = self.Linksize(headA) #调用类里面的函数要用self
        sizeB = self.Linksize(headB)

        if sizeA > sizeB:
            dis =sizeA - sizeB
            headA=self.Headmove(headA,dis)
        else:
            dis = sizeB - sizeA
            headB = self.Headmove(headB,dis)

        while headA != headB:
            headA=headA.next
            headB=headB.next
        return headA

你可能感兴趣的:(代码随想录一刷,链表,面试,数据结构)