leetcode算法训练第三天| 203.移除链表元素 , 707.设计链表 , 206.反转链表

203. 移除链表元素

学习视频地址:手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili

学习文档地址:代码随想录 (programmercarl.com)

学习开始时间:13:40-15:30

文档记录时间: 15:30- 15:39

状态:已听懂|可单独复写代码|暂不需复习

1. 看到问题后的初始想法  

        看到这个问题后我想到的第一个方法就是不使用虚拟节点,以判断头节点与中间节点的方式进行删除操作,但由于curr与curr.next很容易是空值并且我当初没有找到一个很好的方法取排除curr是空值时curr.val报错的问题,所以我暂时放弃。后来又想到了数据结构课上讲的虚拟头节点的方法,故尝试使用虚拟头节点的方法,做的很方便也很流畅,比起前者方法繁琐的的判断条件与大量可能出现的错误相比后者虚拟节点简直是神中神。

2.  看完随想录后的迭代想法

        看了视频与文档后和我整体的思路差不多,但是我看完才最终发现第一个方法居然这么烦!我自己写绝对绕晕了,感谢虚拟节点!🙏

talk is cheap, show me the code:

def removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """
        dummy = ListNode(next=head)
        curr = dummy
        while curr.next != None :
            if curr.next.val == val:
                curr.next = curr.next.next
            else:
                curr = curr.next

        return dummy.next

 leetcode运行结果:

707. 设计链表

学习视频地址:帮你把链表操作学个通透!LeetCode:707.设计链表_哔哩哔哩_bilibili

学习文档地址:代码随想录 (programmercarl.com)

学习开始时间:16:00-17:30

文档记录时间: 20:09- 20:20

状态:已听懂|可单独复写代码|暂不需复习

1. 看到问题后的初始想法   

        第一眼看到后感觉难度不会特别大,因为链表的插入、删除、提取等操作都是基础中的基础。但是自习看了下题目之后发现这题目过于“基础”了,甚至node与listnode都没有定义,全得自己写。由于自己基本功的问题,我到这里就基本上没什么头绪了,因为我一次都没有完整搭建过node。

2.  看完随想录后的迭代想法

        感觉自己的基本功得到了升华。理解MyLinkedList最重要的是清晰的认识到dummyhead与size变量并不是由我们来赋值的,而是根据class中其他的增删操作进行修改,并不需要使用者自己赋值。另一个需要注意的点就是边界问题,在增加数值时,index的上限是可以等于size的,此时相当于进行尾部添加操作,但是在删除数值时,index的上限不可以等于size,因为等于size时会因为无法提取curr.next.next而报错。(因为index等于size时,curr会遍历到链表最后一个位置,此时curr.next为NoneType)

Talk is cheap, show me the code:

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

class MyLinkedList(object):

    def __init__(self):
        self.dummyhead = Node()
        self.size = 0


    def get(self, index):
        """
        :type index: int
        :rtype: int
        """
        curr = self.dummyhead
        if index < 0 or index >= self.size:
            return -1
        for i in range(index):
            curr = curr.next
        return curr.next.val


    def addAtHead(self, val):
        """
        :type val: int
        :rtype: None
        """
        newhead = Node(val=val)
        newhead.next = self.dummyhead.next
        self.dummyhead.next = newhead
        self.size += 1

    def addAtTail(self, val):
        """
        :type val: int
        :rtype: None
        """
        newNode = Node(val=val)
        curr = self.dummyhead
        for i in range(self.size):
            curr = curr.next
        curr.next = newNode
        self.size += 1


    def addAtIndex(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        if index <= self.size and index >= 0:
            newNode = Node(val=val)
            curr = self.dummyhead
            for i in range(index):
                curr = curr.next
            newNode.next = curr.next
            curr.next = newNode
            self.size += 1

    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        if index < self.size and index >= 0:
            curr = self.dummyhead
            for i in range(index):
                curr = curr.next
            curr.next = curr.next.next
            self.size -= 1

# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)

leetcode运行结果:

206. 反转链表

学习视频地址:帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili

学习文档地址:代码随想录 (programmercarl.com)

学习开始时间:20:20-21:20

文档记录时间:21:20-21:40

状态:已听懂|可单独复写代码|需复习

 1. 看到问题后的初始想法   

        看完题目后第一个想法是再创建一个链表,然后通过创建一个存储方向数据的数组给其赋值(需要再创建一个链表与一个数组)。这就消耗了大量的内存,也增加了代码的繁琐程度。自己尝试想了下不占用新的空间(o(n))来解决问题,未果,遂直接看视频讲解。

2.  看完随想录后的迭代想法

        喵啊!这题的迭代思想为:创建3个指针,其中两个是curr和pre指针,用来改变链表链接方向,temp是存储指针,用来给curr下次更新做出定位。具体的操作为:curr初始值为head,pre初始值为head前的None,先将curr.next的值赋给temp作为更新位置的备份,再将curr.next值指向curr之前的pre,最后将pre赋值为curr,curr赋值为temp完成一次基本的操作。(当curr非空时一直循环下去)而递归的思想也是基于迭代的思想而来的,首先递归的函数为reserve(curr, pre), 终止条件是curr为空,其次,在每一次递归中,我们首先需要将temp更新为curr.next,并将curr.next指向pre,然后我们再将temp与curr放入函数(此时temp的位置为需要反转的位置,即函数应为reserve(temp, curr).

Talk is cheap, show me the code

# recursive version
class Solution(object):
    def reserve(self, curr, pre):
        if curr == None:
            return pre
        temp = curr.next
        curr.next = pre
        return self.reserve(temp, curr) ##此处一定要有return!!!雪的教训

    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        result = self.reserve(head, None)
        return result
        
# iterative version
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 双(三)指针法,非递归版本
        curr = head
        pre = None
        while curr:
            temp = curr.next
            curr.next = pre
            pre = curr
            curr = temp
        return pre

leetcode代码运行结果:

虽说leetcode的performance只能图一乐,但没想到循环的表现比我苦心积虑写的递归好那么多。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值