代码随想录Day4 | 反转链表 & 两两交换链表中的节点 & 删除链表倒数第N个节点 & 链表相交 & 环形链表

今天题目这么多是因为昨天少做了一个(嘿嘿)。

LeetCode 206. 反转链表

在这里插入图片描述

双指针法

反转链表的第一种做法是双指针法,难点在于理解临时变量存在的意义,以及需要把哪个元素存储为临时变量。

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head
        pre = None
        while cur:
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
        return pre

递归法

递归法真的简介明了很多!!好喜欢这种有力量的代码。

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        return self.reverse(head, None)

    def reverse(self, cur, pre):
        if not cur: 
            return pre
        temp = cur.next
        cur.next = pre
        #pre = cur
        #cur = temp
        #return self.reverse(cur, pre)
        return self.reverse(temp, cur)

需要注意的是再reverse函数的最后一行,需要做的是把self.reverse递归结果return回去。第一次报错就是因为没有return。后来思考了一下,temp和cur都不是全局变量,不是在递归的过程里可以自行修改的,因此需要反复return使得上层函数可以接收到。
同时注释掉的那三行也可以用,就和双指针完全对应,会好理解一些。

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

这道题的重点是理解什么时候需要存储中间变量,理解了这点才能知道为什么本题需要两个temp变量。可以在纸上写写画画,来理解各个next的内涵。

class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummy_head = ListNode(next = head)
        cur = dummy_head
        while cur.next and cur.next.next:
            mid = cur.next
            cur.next = cur.next.next

            temp = cur.next.next
            cur.next.next = mid
            mid.next = temp
            cur = mid
        return dummy_head.next

报错了一次,原因在于最后让cur=temp了。注意因为是两两交换,所以一次迭代的cur应该是上一轮交换后结尾的节点,而不是这一轮交换的第一个节点。改成cur=mid就通过啦。

LeetCode 19. 删除链表的倒数第 N 个结点在这里插入图片描述

这道题的重点是看清楚题意,是删除倒数第n个节点哇!!
我第一种方法是自己写的,先计数,找到倒数第n个节点的正数位置再删除。复杂度应该也是O(n)。

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(next = head)
        cur = dummy
        size = 0
        while cur.next:
            size += 1
            cur = cur.next
        cur = dummy
        for _ in range(size - n):
            cur = cur.next
            if not cur:
                return head
        cur.next = cur.next.next
        return dummy.next

第二种方法是快慢双指针,这样可以保证快指针比慢指针多走n步。

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(next = head)
        slow, fast = dummy, dummy
        for i in range(n+1):
            fast = fast.next
        while fast:
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next
        return dummy.next

LeetCode 160. 相交链表

在这里插入图片描述

这道题思路还是很简单的,主要是想明白相交的部分不是当前数值相同,而是指针相同。同时,需要让两个链表一样长,因此需要先计数,然后让长的先往前走几步。

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
        cur = headA
        lenA = 0
        while cur:
            lenA += 1
            cur = cur.next
        cur = headB
        lenB = 0
        while cur:
            lenB += 1
            cur = cur.next

        if lenA > lenB:
            for _ in range(lenA - lenB):
                headA = headA.next
        else:
            for _ in range(lenB - lenA):
                headB = headB.next
        
        while headA:
            if headA == headB:
                return headB
            headA = headA.next
            headB = headB.next
        return None

LeetCode 142. 环形链表

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

这道题很牛!!最最最最主要的是推导出x = (n-1)(y+z)+z,也就是说,z和x是相等的,如果一个从head另一个从交点出发,最终会在环形入口相遇。这个idea真的很绝啊!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值