代码营打卡 Day3

1. 移除链表元素(203)

用虚拟头节点, 首先值得注意的是python中创建虚拟头节点的方式

dummy_head = ListNode(next=head) 这行代码的作用是创建一个虚拟的头节点(dummy head),并将其 next 指针指向链表的真实头节点 head

用current这个临时指针进行遍历, 因为头指针如果改了就找不到链表了

另外值得注意的是要确定current.next不能为空值,否则下一步current.next.next就是对空取next,是不合法操作

还有一点就是current存储dummy_head的指针而不是dummy_head.next, 这是因为要删除时, 要知道这个节点的前节点和后节点,并且让前节点指向后一个节点. 那么如果知道current, 能删除的是current.next而不是current本身(因为无法知道前一个节点)

最后return的是dummy_head.next, 虚拟节点后面的节点是新链表的节点, 而不是原来的head节点(有可能已经被删除)

用虚拟节点的好处是节省了代码量,如果不用虚拟节点要考虑删除的节点是否为头节点, 如果删除的是头节点,需要head = head -> next, 而如果不是头节点, 处理方法则与虚拟节点处理方法类似, 即cur = cur -> next

        dummy_head = ListNode(next = head)
        current = dummy_head
        while(current.next):
            if current.next.val == val:
                current.next = current.next.next
            else:
                current = current.next
        return dummy_head.next

2. 设计链表(707)

首先对链表进行初始化

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

class MyLinkedList(object):

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

2.1 获取第n个节点的值

首先确定合法的index取值范围, 可以发现 index<0 或者index>size-1的时候不合法

本道题是要获取第n个节点的值, 那么也就是获取cur点的value值, 当cur为0的时候, 获取的就是head节点对应的值, 所以head是dummyhead.next, 所以cur = dummyhead.next

这里while也可以改写为for循环: for i in range(index), 可以省略index -= 1的操作

    def get(self, index):
        """
        :type index: int
        :rtype: int
        """
        if index < 0 or index>= self.size:
            return -1
        cur = self.dummy_head.next
        while index:
            cur = cur.next
            index -= 1
        return cur.val

2.2 头部插入节点

在插入节点要注意顺序, 如果先写dummyhead.next = newnode, 会出现当再写newnode.next = dummyhead.next的时候找不到节点的问题(这里是头节点尚且还可以用head表示,但是如果是在n节点中插入会出现丢失节点的情况)

所以要先写后者再写前者

在python中似乎不存在这样的问题, 指定dummyhead下一个点的next点是当前dummyhead.next(即head节点)即可, 实际上也包含了从右边到左边的顺序

另外要注意的是增删节点时要注意更新size的大小

    def addAtHead(self, val):
        """
        :type val: int
        :rtype: None
        """
        self.dummy_head.next = ListNode(val, self.dummy_head.next)
        self.size += 1

2.3 尾部插入节点

这里似乎cur是dummyhead还是dummyhead.next都不影响, 因为最后终止的条件和index没有关系,判断尾部的条件是cur.next = null(在python中应该是none)

当找到了尾部的节点, 让新节点的next为none即可

插入节点以后更新size值

    def addAtTail(self, val):
        """
        :type val: int
        :rtype: None
        """
        cur = self.dummy_head
        while cur.next :
            cur = cur.next
        cur.next = ListNode(val)
        self.size += 1

2.4 第n个节点前插入节点

涉及到在第n个节点插入节点的问题, 首先要考虑边界的问题

其次, 要想在第n个节点前插入新节点, 还得知道n-1个节点是什么, 也就是说插入的n节点是cur.next, n=0时, current.next是head节点, 那么cur= dummyhead

所以将newnode的next设置为cur.next, 将cur.next设置为newnode即可

注意设置的顺序, 在python中即 将新节点的next节点设置为cur.next, 并且让cur的next指向新节点即可

增删以后记得更新size的值

    def addAtIndex(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        if index < 0 or index > self.size:
            return

        cur = self.dummy_head
        while index:
            cur = cur.next
            index -= 1
        cur.next = ListNode(val, cur.next)
        self.size += 1

2.5 删除第n个节点

删除第n个节点, 需要注意越界问题

删除第n个节点的时候, 需要知道第n个节点的前后两个节点, 也就是current 和 current.next.next, 也就是n对应的是current.next, 所以n=0是head, current=dummyhead

删除第n个节点就是直接让current节点指向current.next.next节点, 也就是current.next = cureent.next.next

增删记得结尾需要更新size

    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        if index < 0 or index >= self.size:
            return
        cur = self.dummy_head
        for i in range(index):
            cur = cur.next
        cur.next = cur.next.next
        self.size -= 1

3.反转链表(206)

3.1 双指针法

首先初始化cur和pre, cur指向head, pre指向head之前, head翻转以后成为尾节点, 指向null, 所以把pre初始化为none

然后就是将cur指向pre完成反转, 这里注意几个问题:

1. 终止条件: 当pre到了尾节点, cur指向null的时候, 就不需要再反转了, 遍历应该已经结束. 也就是说当cur为空的时候, 应该结束遍历

所以结束的条件应该是cur == null

2. 先要用temp存下cur.next的值, 再进行反转, 否则cur指向pre以后, 无法得知cur反转之前的下一个节点的指针, 无法继续

3. 移动时, 应该先移动pre, 再移动cur, 因为如果先移动cur, 无法用pre=cur得知cur之前所在的位置了,pre就无法到达cur之前所在位置

4. 反转完成以后, pre成为新的链表的头节点, 所以直接return pre

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        cur = head 
        pre = None
        while cur:
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
        return pre
        

3.2 递归

这里递归由双指针简化和演变而来, 主要是省略了移动cur和pre的操作, 而直接用递归完成.  首先用if写清楚递归的结束条件, 即在cur为null的时候return pre, 即结束递归

其次要完成pre->cur的反转, 先用一个临时指针temp记录反转之前的cur.next, 便于下一步递归的连续. 然后用cur.next = pre完成反转.

在下一步的递归中, 将cur作为pre, 将temp作为cur, 完成递归

初始递归条件为cur为head, pre为none, 在主函数reverselist的返回值写入

 def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        def reverse(cur, pre):
            if cur == None:
                return pre
            temp = cur.next
            cur.next = pre
            return reverse(temp, cur)

        return reverse(head, None)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值