代码随想录算法训练营Day4 | 24. 两两交换链表中的节点,19. 删除链表的倒数第N个节点,160. 相交链表,142. 环形链表II

目录

24. 两两交换链表中的节点

19. 删除链表的倒数第N个结点

160. 相交链表

142. 环形链表II


24. 两两交换链表中的节点

题目链接:24. 两两交换链表中的节点 - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:没有理解链表的思想,如何处理奇数链表

        ①如何交换链表元素

        按下图三个步骤所示进行节点的交换

        ②循环何时退出

        因为是每两个节点进行交换,所以要同时保证这两个节点都不为空。若链表为偶数,则全部两两交换,若链表为奇数,最后一个节点的next为空,跳出循环,即这个节点不用交换。另外,在两两交换的情况下,cur指针每次后移两个节点。

# 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]:
        dummy = ListNode(None, head)
        cur = dummy
        while cur.next and cur.next.next:
            temp = cur.next # 防止待交换的节点被修改
            temp2 = cur.next.next.next
            cur.next = cur.next.next # 步骤1
            cur.next.next = temp # 步骤2
            cur.next.next.next = temp2 # 步骤3
            cur = cur.next.next # 移动指针
        return dummy.next

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)

19. 删除链表的倒数第N个结点

题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:如何一遍找到倒数第N个结点

        双指针法。让slow和fast同时指向虚拟头结点,要删除倒数第N个结点,则让fast先走N步,随后同时让slow和fast移动。当fast指向最后一个结点时,slow对应的就是倒数第N个结点。另外,链表中要删除某一个结点,指针需位于该结点的前一个结点。

        清楚思路了代码就好写。

# 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 = ListNode(0, head)
        slow = dummy
        fast = dummy
        for _ in range(n): # fast结点先走N步
            fast = fast.next
        while fast.next: # slow和fast同时移动,直至fast位于链表最后一个元素
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next
        return dummy.next

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)

160. 相交链表

题目链接:面试题 02.07. 链表相交 - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:看不懂题

        注意:不是判断curA.val == curB.val,而是判断curA == curB,即链表交点的指针要相等。这里的相等也包含了地址相等,具体是哪个交点由题目设定,对于解题来说只需要按思路把每个点判断一遍即可。

        解题思路:

        ①定义两个指针,位于两个链表的头节点;

        ②遍历两个指针,求出两个链表的长度,计算长度差n;

        ③让更长的链表头指针先走n个单位;

        ④同时让两个指针向后移动,直至两指针相同,返回交点;

        ⑤遍历结束也没有交点返回None。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        lenA = self._get_length(headA)
        lenB = self._get_length(headB)
        if lenA > lenB: # 步骤3
            headA = self._move_forward(headA, lenA-lenB)
        else:
            headB = self._move_forward(headB, lenB-lenA)
        curA = headA
        curB = headB
        while curA and curB: # 步骤4
            if curA == curB:
                return curA
            curA = curA.next
            curB = curB.next
        return None
    
    def _get_length(self, head: ListNode): # 计算链表的长度
        length = 0
        cur = head
        while cur:
            length += 1
            cur = cur.next
        return length

    def _move_forward(self, head: ListNode, step: int): # 将链表头指针向后移动
        cur = head
        while step:
            cur = cur.next
            step -= 1
        return cur

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)

142. 环形链表II

题目链接:142. 环形链表 II - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:没思路

        ①判断链表是否有环

        就好比跑步,操场是个环,跑的快的一方迟早会追上跑圈慢的一方,也就是迟早会相遇。

        双指针法,快慢指针。每当慢指针前进一步,快指针前进两步。如果快指针遇到None,说明快指针到链表末尾,无环;如果快指针遇到慢指针,说明存在环。根据相对运动,快指针每次比慢指针多走一步,即在环中快指针每次都会接近慢指针一步,所以当存在环的时候,他们一定会相遇。

        ②如何找到环的入口

        推导见代码随想录。在相遇节点处定义一个指针index1,在链表头结点处定一个指针index2,让index1和index2同时移动,每次移动一个节点, 那么1、2相遇的地方就是环形入口的节点。

# 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]:
        slow = head
        fast = head
        while fast and fast.next: # 当fast和next为None,说明fast到了链表末尾,无环
            slow = slow.next
            fast = fast.next.next
            if slow == fast: # 当环存在,slow和fast一定相遇
                slow = head # 此时slow为index2,fast为index1
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        return None

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值