代码随想录Day3: 链表Part1

Leetcode 203: 移除链表元素

讲解前:

这道题我之前其实就做过,算是一道非常基础的链表题目,在链表中我们明白每一个元素的access其实都需要上一个node来寻找,因为只有node.next才能获取到他,所以删除一个元素最简单的方法就是让其上一个node的next指针跳过他直接指向下下个元素也就是 1->2->3 删除2以后,1的next就应该直接指向3,也就是1->3 

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        res = ListNode(0, head)

        prev = res
        current = head

        while current:

            if current.val == val:
                prev.next = current.next
                current = current.next
            else:
                prev = prev.next
                current = current.next

        return res.next    

我这里的解法就是利用了一个虚拟的头节点来让其的next指向真正的head,这样以来,哪怕需要删除的节点是头节点,我们也能运用一样的方法了,current node是用来遍历整个链表的所以循环的条件是while current,然后呢prev用来帮助我们have access to the node before current,这样我们才能通过改变prev.next 来删除current node,于是我们让prev初始化为我们创建的指向head的虚拟节点然后让current指向head,在遍历中,每当我们发现current node的值需要被删除,我们就让prev.next指向current.next这里就不需要更新prev了,然后无论是否需要被删除,每次我们都更新current = current.next

讲解后:

看完了卡哥的讲解后发现他不管是不用dummy node的方法还是用的方法,他都只新建了一个current node,然后每一次比较数值的时候检查 curr.next. 然后删除的操作是curr.next = curr.next.next 这个方法其实会让我有些晕,因为while 循环的定义会模糊,检查的是while curr.next != null 所以总让人有种没有彻底遍历到最后一个元素的感觉,但其实这里的curr扮演的角色是我的code中prev扮演的角色


Leetcode 707: 设计链表

讲解前:

这道题其实就是需要我们自己写一个linked list的类,类似的情况在学校的数据结构算法课中都有涉及到,不过为了第一次先成功尝试以及自己完成,我决定先用写单项链表的类试一下

虽然经历了一些debug但是最终还是成功的写出来了,我认为这道题其实并不难,没有什么需要特别注意的算法,在get 和 addatindex中需要先遍历到index然后再执行一个简单的操作就好了

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class MyLinkedList:

    def __init__(self):
        self.dummy_head = ListNode()
        self.size = 0

    def get(self, index: int) -> int:
        if self.size <= index:
            return -1
        
        current = self.dummy_head.next
        for _ in range(index):
            current = current.next
        
        return current.val

    def addAtHead(self, val: int) -> None:
        new_node = ListNode(val, self.dummy_head.next)
        self.dummy_head.next = new_node
        self.size = self.size + 1 


    def addAtTail(self, val: int) -> None:
        current = self.dummy_head
        while current.next:
            current = current.next
        
        current.next = ListNode(val, None)
        self.size = self.size + 1



    def addAtIndex(self, index: int, val: int) -> None:
        if index > self.size:
            return

        new_node = ListNode(val, None)
        current = self.dummy_head
        for _ in range(index):
            current = current.next
        
        temp = current.next
        current.next = new_node
        new_node.next = temp

        self.size = self.size + 1


    def deleteAtIndex(self, index: int) -> None:
        if index >= self.size:
            return
        current = self.dummy_head
        for _ in range(index):
            current = current.next
        
        current.next = current.next.next
        
        self.size = self.size - 1
讲解后:

卡哥的思路和我的一样只是在他的讲解中他基本都用了while loop来做,但是我都用了for loop,不过有一个地方我发现我做的时候莫名其妙的复杂化了就是add at index的操作中,我莫名其妙的用了一个temp node,但压根没必要,当我们找到要加的index的前一个node之后直接这样加就可以了

    def addAtIndex(self, index: int, val: int) -> None:
        if index > self.size:
            return

        new_node = ListNode(val, None)
        current = self.dummy_head
        for _ in range(index):
            current = current.next
        
        new_node.next = current.next
        current.next = new_node

        self.size = self.size + 1

Leetcode 206:翻转链表

讲解前:

我记得我之前也做过这道题,我的记忆中需要用到一个temp node去记录什么然后好像又是要从链表的后面往前遍历之类的,我打算一定要自己写出来不看讲解

这道题我还是成功的使用了双指针的解法做了出来,可能是前两道题都利用了dummy node的关系,我在这道题中还是不假思索的写了一个dummy node, 这是我一开始的写法

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

        dummy = ListNode(None, head)
        current = head
        prev = dummy

        while current:
            temp = current.next
            current.next = prev
            prev = current
            current = temp
        

        return prev

我反复debug了很多遍才发现我这样写有一个非常大的问题就是dummy node的next指向head这一点我从来没有变过,也就是说我们翻转完了整个链表最后返回的时候,找回到一开始的旧的head时,他指向的其实是dummy node,我以为dummy的值是None所以这样刚好,但是我忘记了dummy node的next又重新指回了head,这就产生了一个自循环的链表(环形链表),所以我们return的结果永远遍历不完,哪怕我把dummynode的next改成None也不行,因为最后返回的值中最后会多一个null,后来我发现其实这里根本没必要有dummy node,prev一开始就直接设置成null就可以了,然后这是更新过的正确的代码

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        current = head
        prev = None

        while current:
            temp = current.next
            current.next = prev
            prev = current
            current = temp
        

        return prev
讲解后:

看了卡哥的讲解之后对于双指针的解法每个指针的用处还有循环中每一行代码的作用有了更深的理解,然后还按照卡哥说的通过双指针的思路写出了递归的解法

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

    def reverse(self, prev, current):
        if not current:
            return prev
        else:
            temp = current.next
            current.next = prev
            return self.reverse(current, temp)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值