链表01 | 203.移除链表元素、707.设计链表、*206.反转链表、138. 随机链表的复制

文章讲述了在Python中处理链表时使用虚拟头节点的方法,包括移除指定值的节点、设计链表类以及反转链表,强调了虚拟头节点在操作链表时的重要性,特别是处理头节点时的技巧和代码实现问题。
摘要由CSDN通过智能技术生成

203.移除链表元素

题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html

  • 考点
    • 虚拟头节点
  • 我的思路
    • 头节点和其它节点分开讨论
  • 视频讲解关键点总结
    • 未看视频
    • 在头节点前创建一个虚拟头节点指向头节点
    • 之后创建循环所用链表变量prev,并将虚拟头节点赋值给prev
    • 开始循环,循环条件为prev.next不为None
    • 进入循环,如果prev.next.val == val,则让prev.next = prev.next.next,否则,让prev变成prev.next
    • 最后输出虚拟头节点所指向的头节点即为答案
  • 我的思路的问题
    • 头节点和其它节点分开讨论会增加算法的时间复杂度
  • 代码书写问题
  • 可执行代码
class Solution(object):
    def removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """
        dummy_node = ListNode(next=head)
        prev = dummy_node
        while prev.next is not None:
            if prev.next.val == val:
                prev.next = prev.next.next
            else:
                prev = prev.next
        return dummy_node.next

707.设计链表

题目链接/文章讲解/视频讲解:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html

  • 考点
    • 链表的虚拟头节点
  • 我的思路
    • 链表类初始化头节点和链表长度
    • 之后如果需要用到虚拟头节点,在每个实现方法里创建虚拟头节点
  • 视频讲解关键点总结
    • 未看视频
    • 关键点在于类初始化里直接初始化虚拟头节点和链表长度,不初始化头节点
  • 我的思路的问题
    • 在删除节点的时候,如果删除的是头节点,则我用新创建的虚拟头节点就无法成功删除,必须要按照类初始化里初始化虚拟头节点的方式才行
  • 代码书写问题
  • 可执行代码
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next


# leetcode submit region begin(Prohibit modification and deletion)
class MyLinkedList(object):

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

    def get(self, index):
        """
        :type index: int
        :rtype: int
        """
        n = 0
        prev = self.dummy_head
        while prev.next is not None:
            if n == index:
                return prev.next.val
            else:
                n += 1
                prev = prev.next
        return -1


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


    def addAtTail(self, val):
        """
        :type val: int
        :rtype: None
        """
        new_last = ListNode(val=val)
        prev = self.dummy_head
        while prev.next is not None:
            prev = prev.next
        prev.next = new_last
        self.length += 1

    def addAtIndex(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        if index > self.length:
            return
        n = 0
        new_node = ListNode(val=val)
        prev = self.dummy_head
        while prev.next is not None:
            if n == index:
                new_node.next = prev.next
                prev.next = new_node
                self.length += 1
                return new_node
            else:
                n += 1
                prev = prev.next
        if n == index:
            prev.next = new_node
            self.length += 1
            return new_node
        return -1



    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        n = 0
        prev = self.dummy_head
        while prev.next is not None:
            if n == index:
                prev.next = prev.next.next
                self.length -= 1
                return 0
            else:
                n += 1
                prev = prev.next
        return -1

*206 反转链表

题目链接/文章讲解/视频讲解:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html

  • 考点
    • 法一:双指针
    • 法二:基于双指针的解法改为对应的递归函数
  • 我的思路
    • 无思路
  • 视频讲解关键点总结
    • 法一:双指针
      • prev指针从NULL开始,cur从head开始
      • 创建一个临时变量a保存cur的next
      • 让cur的next等于prev
      • 让prev等于cur
      • 让cur等于a
    • 法二:递归(结合法一看,其实就是对双指针法的递归实现)
      • 递归函数的功能:输入两个指针prev和cur,返回反转后链表的头指针;为此,函数体内进行cur节点重定向的操作
      • 递归结束条件,cur移动到最后一个节点
  • 我的思路的问题
    • 没想到用一个初始化为NULL的prev
  • 代码书写问题
  • 可执行代码
  • 法一:双指针法
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        cur = head   
        pre = None
        while cur:
            temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->next
            cur.next = pre #反转
            #更新pre、cur指针
            pre = cur
            cur = temp
        return pre
  • 法二:递归法
class Solution(object):
    def rev(self, prev, cur):
        if cur is None:
            return prev
        temp = cur.next
        cur.next = prev
        return self.rev(cur, temp)
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        return self.rev(None, head)

138. 随机链表的复制

  • 题干
    在这里插入图片描述
  • 思路
    • 因为有random指针的存在,所以单次的遍历无法一次完成链表的复制
    • 因此分两次遍历完成复制
    • 第一次遍历复制val属性和next指针
    • 第二次遍历复制random指针
      • 复制random指针有基础方法和优化后的方法
      • 基础方法
        • 定义两个指针分别指向原链表head和复制链表head
        • 之后同步向后移动两个指针,直到原链表指针和原链表的当前random指针相同时,则复制链表指针对应的node就是复制链表的当年random指针
        • 由于该方法需要内外两层遍历,因此时间复杂度为O(n^2)
      • 优化方法
        • 在第一次遍历时,利用字典(哈希表)储存原链表node(key)和复制链表node(value)的对应关系
        • 在第二次遍历时,每遍历一个原链表节点,其random指针可以直接从字典中取到对应的复制链表node,该node即为复制链表的random指针
        • 由于该方法只需要外层遍历,内层直接利用字典实现了O(1)的查找效率,所以整体方法的时间复杂度为O(n)
  • 代码
# 基础方法
class Solution:
    def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        if not head:
            return None
        new_head = Node(head.val)
        cur = head
        cur_new = new_head
        while cur:
            next_ = Node(cur.next.val) if cur.next else None
            cur_new.next = next_
            cur_new = cur_new.next
            cur = cur.next
        cur = head
        cur_new = new_head
        while cur:
            if cur.random:
                random_node = cur.random
                nod = head
                nod_new = new_head
                while nod != random_node:
                    nod = nod.next
                    nod_new = nod_new.next
                random_node = nod_new
            else:
                random_node = None
            cur_new.random = random_node
            cur = cur.next
            cur_new = cur_new.next

        return new_head
#优化方法
class Solution:
    def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        if not head:
            return None
        new_head = Node(head.val)
        cur = head
        cur_new = new_head
        dic = dict()
        while cur:
            next_ = Node(cur.next.val) if cur.next else None
            cur_new.next = next_
            dic[cur] = cur_new
            cur_new = cur_new.next
            cur = cur.next
        cur = head
        while cur:
            dic[cur].random = dic[cur.random] if cur.random else None
            cur = cur.next
            
        return new_head
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值