代码随想录算法训练营第四天| LeetCode24. 两两交换链表中的节点 、LeetCode19.删除链表的倒数第N个节点 、面试题 02.07. 链表相交、LeetCode142.环形链表II

一:LeetCode24. 两两交换链表中的节点 

        1:题目描述(24. 两两交换链表中的节点

        给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

        2:解题思路

        这道题首先需要确认的一点是,交换的是两个节点,不是两个节点的值。

        我们使用虚拟头节点,然后定义临时指针cur,指向虚拟头节点,难点在于每次循环时cur指针的位置,以及修改节点next指向的顺序。

        这里我犯了一个逻辑思维小错误,就是自己以为,每个节点只能有一个节点指向自己和自己只能指向一个节点。后面才反应过来,节点自己的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):
        mydeay_node = ListNode(next=head)       # 定义虚拟头节点,next指向链表头节点
        cur = mydeay_node                       # 定义临时指针,指向虚拟头节点
        while cur.next != None and cur.next.next != None:
            temp1 = cur.next                    # 定义一个临时指针,指向当前节点的下一个节点
            temp2 = cur.next.next               # 定义一个临时指针,指向当前节点的下一个节点的下一个节点
            # 下面交换相邻节点,修改节点的next指向
            temp1.next = temp2.next             
            temp2.next = temp1
            cur.next = temp2
            # 修改临时指针cur
            cur = cur.next.next
        return mydeay_node.next

二、LeetCode19.删除链表的倒数第N个节点

        1:题目描述(19.删除链表的倒数第N个节点

        给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

        2:解题思路

        我们只需要找到倒数第n个节点的前面一个节点(倒数第n+1个节点),将倒数第n+1个节点的next指向倒数第n个节点的下一个节点(倒数第n-1个节点),即可将倒数第n个节点删除。

        解法一:先统计出链表的长度,然后使用for循环,遍历链表,找到倒数第n+1个节点,结束循环,修改倒数第n+1个节点的next指针。

# 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, n):
        # 删除倒数第n个节点,我们需要先找到倒数第n+1个节点
        mydeay_node = ListNode(next=head)           # 定义一个虚拟头节点
        cur, pre = mydeay_node, mydeay_node         # 定义两个临时指针,cur用来遍历链表统计链表的长度,pre用来找到倒数第n+1个节点
        count = 0                                   # 统计链表长度的变量
        while cur.next != None:                     # 当res指针对应节点的下一个节点不为None,说明还未遍历到尾节点
            count += 1                              # 链表长度+1
            cur = cur.next                          # cur指向下一个节点
        # 统计完链表的长度了,我们需要找到倒数第n个节点的前一个节点
        for i in range(count-n):                    # 遍历链表,找到倒数第n+1个节点
            pre = pre.next                          
        pre.next = pre.next.next                    # 找到后,将倒数第n+1个节点的next指针指向它下一个节点的下一个节点(第n-1个节点),即可删除倒数第n个节点
        return mydeay_node.next

        解法二:使用双指针-快慢指针

        还是添加一个虚拟头节点,快慢指针均指向链表的虚拟头节点,快指针先走n+1步,然后慢指针再出发,慢指针与快指针同时移动,当快指针指向为None时,慢指针到达了倒数第n+1个节点,然后修改慢指针指向的节点的next指针即可。

# 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, n):
        # 使用双指针-快慢指针
        # 快指针先走n+1步,然后快慢指针同时移动,直到快指针指向了None,慢指针移动到了倒数第n个节点的前一个节点
        mydeay_node = ListNode(next=head)            # 定义虚拟头节点
        fast, slow = mydeay_node, mydeay_node        # 定义快慢指针
        for i in range(n+1):         
            fast = fast.next                         # 快指针向后走n+1步
        while fast != None:                          # 快指针不为空,同时移动快慢指针
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next                   # 快指针为空,慢指针到了倒数第n个节点的前一个节点,让慢指针的next指向慢指针的下一个节点的下一个节点
        return mydeay_node.next

  三、面试题 02.07. 链表相交

        1:题目描述(面试题 02.07. 链表相交

        给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

        图示两个链表在节点 c1 开始相交

        

        题目数据 保证 整个链式结构中不存在环。

        注意,函数返回结果后,链表必须 保持其原始结构 。

        2:解题思路

        解法一:使用双指针,分别指向两个链表的头节点,然后同时向移动一个节点,当有指针指向为None时,则指向另外一个链表的头节点,如果两个链表有相交的节点,则两个指针一定会相遇。

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

class Solution:
    def getIntersectionNode(self, headA, headB):
        # 使用双指针
        # 两个指针分别从两个链表的头节点出发,到达各自链表的尾节点后,指向另外一个链表的头节点,继续往后走,这样两个指针会在链表的相交点相遇
        if headA is None or headB is None:
            return None
        cur1 = headA
        cur2 = headB
        while cur1 != cur2:
            if cur1 == None:           # cur1等于None,则将cur1指向链表B的头节点
                cur1 = headB
            else:                      # cur1不等于None,则继续向后移动
                cur1 = cur1.next
            if cur2 == None:           # cur2等于None,则将cur2指向链表A的头节点
                cur2 = headA
            else:                      # cur2不等于None,则继续向后移动
                cur2 = cur2.next
        return cur1

        解法二:也是使用双指针,不过跟解法一不同的是,先分别统计两个链表的长度,然后将两个链表尾部对齐,较长链表的指针先走,走到与较短链表长度一致的位置,两个链表的指针再同时向后移动,直到两个指针相等,则表示找到了相交点。

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

class Solution:
    def getIntersectionNode(self, headA, headB):
        # 先统计两个链表的长度,将两个链表尾部对齐,然后较长链表,先走到与较短链表长度相同的位置,然后两个链表同时移动,如果有相交节点,则会有节点相等
        if headA is None or headB is None:
            return None
        cur_a, cur_b = headA, headB
        cur1, cur2 = headA, headB
        count_a, count_b = 0, 0
        # 统计两个链表的长度
        while cur_a != None:
            count_a += 1
            cur_a = cur_a.next
        while cur_b != None:
            count_b += 1
            cur_b = cur_b.next
        # 判断两个链表的长度谁大
        if count_a >= count_b:
            for i in range(count_a - count_b):
                cur1 = cur1.next                  # 长的链表,先走count_a - count_b个节点
            while cur1 != cur2:
                cur1 = cur1.next
                cur2 = cur2.next
        else:
            for i in range(count_b - count_a):
                cur2 = cur2.next                  # 长的链表,先走count_a - count_b个节点
            while cur1 != cur2:
                cur1 = cur1.next
                cur2 = cur2.next
        return cur1

四、LeetCode142.环形链表II 

        1:题目描述(142.环形链表II 

        给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

        如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

        不允许修改 链表。

        2:解题思路

        使用双指针-快慢指针,快指针每次向后移动2个节点,慢指针每次向后移动1个节点,如果链表有环存在,则快指针会先进入环,然后在环中一直转圈,慢指针后进环,慢指针进入环后,会在慢指针进入环的第一圈与快指针相遇,此时使用一个指针index1,指向快慢指针相遇的节点,同时使用指针index2指向链表的头节点,然后同时移动index1和index2,每次移动一个节点,直到index1=index2,我们就找到了环的入口节点。

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

class Solution:
    def detectCycle(self, head):
        # 使用双指针-快慢指针
        # 快指针每次比慢指针多走一步,即快指针每次走两步,慢指针每次走一步
        # 如果链表中存在有环的情况,则快指针则会比慢指针先入环
        # 慢指针入环后,会在慢指针入环后的第一圈与快指针重叠
        # 此时在定义两个指针,一个指向头节点,一个指向快慢指针相重叠的节点
        # 两个指针同时移动,每次移动一个节点,会在环的入口处重叠,此时就找到了环的入口节点
        fast, slow = head, head
        while fast != None and fast.next != None:
            fast = fast.next.next
            slow = slow.next
            if slow == fast:
                index1 = slow
                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、付费专栏及课程。

余额充值