代码随想录算法训练营Day3 | 203. 移除链表元素,707. 设计链表,206. 反转链表

目录

203. 移除链表元素

707.设计链表

206.反转链表


203. 移除链表元素

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:没分清链表结构,例如虚拟头节点没有用类实例化,使用node.next == val进行了判断

        移除链表元素,需要知道它的上一个元素。该元素需要被移除时,让上一个节点的指针指向下一个节点。即上一个节点node.next.val==val时,node.next=node.next.next。若链表头节点需被移除,将节点指针向后移动一位,也就是第二个节点作为头节点。另外也可以使用虚拟头节点法,对全列表进行统一操作。

        全篇是对current_code进行处理,为什么最后的dummy_head.next是正确答案?准确的说内存中只有1个链表,虚拟头节点在创捷后接上了原链表,是1个链表,current_node是副本链表,是(虚拟头节点+原链表)的弱引用,他们指向的是同1个对象实例。由于弱引用,改变current_node的指针会让(虚拟头节点+原链表)的指针同时受到影响。为何需要current_node,不对原链表处理呢?由于node=node.next,直接使用原链表会使原链表中只有最后一个元素。下面的print(current_node)也是这一情况的体现。故对(虚拟头节点+原链表)潜复制为current_node,current_node的指针变化反映在(虚拟头节点+原链表)上,元素变化不反映在其上。

        以[7,2,7,3]移除7为例,每次循环以及最终结果如下。可以看到对于链表第一个元素,dummy_head可以移除,head移除不了,故最后返回dummy_head.next。图片结果与代码中输出结果相同。

        总结:链表元素的移除就是改变指针next。next里实际储存的是下一个节点的类实例。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# 以[7,2,7,3]移除7为例

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        # print(head)
        dummy_head = ListNode(None, head) # 创建虚拟头节点,下一个节点是原本的头节点
        current_node = dummy_head # 遍历所有节点的指针
        while current_node.next: # 当前节点仍有下一个元素时继续循环
            if current_node.next.val == val: # 当前节点的下一个元素为目标值时
                current_node.next = current_node.next.next # 当前节点下一个节点变为下下个节点,当前节点没有变化
            else:
                current_node = current_node.next # 只有当前节点的下一个元素不为目标值时,当前节点才往前进一位
        # print(current_node)
        # print(head)
        # print(dummy_head)
        return dummy_head.next # 返回真实的头节点

    # ListNode{val: 7, next: ListNode{val: 2, next: ListNode{val: 7, next: ListNode{val: 3, next: None}}}}
    # ListNode{val: 3, next: None}
    # ListNode{val: 7, next: ListNode{val: 2, next: ListNode{val: 3, next: None}}}
    # ListNode{val: None, next: ListNode{val: 2, next: ListNode{val: 3, next: None}}}

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)

 707.设计链表

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:不清楚init里需要初始化什么内容

        init里需要初始化一个空的虚拟头节点,方便后续的操作,同时还需要初始化一个size,用来保存链表中用多少个元素,方便后续的下标判断。除此之外不难。

        此外,使用for i in range(index)进行当前节点的后移会比使用count计数判断简单易读。

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 index > self.size-1:
            return -1
        count = 0
        current_node = self.dummy_head
        while count <= index:
            current_node = current_node.next
            count += 1
        return current_node.val

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

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

    def addAtIndex(self, index: int, val: int) -> None:
        if index > self.size:
            return -2
        elif index == self.size:
            self.addAtTail(val)
        else:
            new_node = ListNode(val, None)
            count = 0
            current_node = self.dummy_head
            while count < index:
                current_node = current_node.next
                count += 1
            new_node.next = current_node.next
            current_node.next = new_node
            self.size += 1

    def deleteAtIndex(self, index: int) -> None:
        if index > self.size-1:
            return -3
        count = 0
        current_node = self.dummy_head
        while count < index:
            current_node = current_node.next
            count += 1
        current_node.next = current_node.next.next
        self.size -= 1

# 答案写的
class MyLinkedList:
    def __init__(self):
        self.dummy_head = ListNode()
        self.size = 0

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

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

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

    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0 or index > self.size:
            return
        
        current = self.dummy_head
        for i in range(index):
            current = current.next
        current.next = ListNode(val, current.next)
        self.size += 1

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

    # 时间复杂度 涉及index相关操作为O(index),其余为O(1)
    # 空间复杂度 O(n)

206.反转链表

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:原地反转链表没思路

        反转链表不需要重新定义一个新的链表,只需要修改原链表的next指针。(纠正:动画应该是先移动pre,让pre为cur,再移动cur,让cur为temp)

        解题可分为四个步骤:①新链表pre,初始化时为新链表的最后一个None,原链表的当前节点cur,初始化时为原链表的第一个节点,pre在前,cur在后;②将pre赋值给cur的next,实现一次局部反转;③局部反转完成后,pre和cur同时往前移动一个位置,pre到cur的位置,cur到next的位置;④循环上述过程,直至cur为None,此时pre就是新的反转链表的头节点。

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

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        pre = None # 反转后链表的最末端
        cur = head # 当前链表的第一个节点
        while cur:
            temp = cur.next # 保存当前节点的后续链表
            cur.next = pre # 让当前链表的第一个节点指向None完成反转
            pre = cur # 反转后链表的最末端和前一个节点
            cur = temp # 当前节点在原链表上前进一位
        return pre

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值