算法训练记录day3

一、节点的定义

理论

链表基础知识视频(0基础)

  • 一个节点包含元素区域和链接区域

class ListNode:
    def __init__(self, val, next=None):
        self.val = val
        self.next = next
# node = ListNode(2)  只有这样 才能把元素2 设置为节点 
# next 就是指针,这个地方指向了None  为空指针

二、移除链表元素

题目

讲解

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        dummy_head = ListNode(next=head)      # 构造虚拟头节点,并指向头节点。  
""" 头节点已经给出,所以虚拟头节点的指针 就指向 head(头节点)  """
        cur = dummy_head                      # 设置一个游标,进行移动,可以理解为一个指针 也是节点
        while (cur.next != None):            # cur是可以移动的,判断下个节点是否为空
            if cur.next.val == val:          # 如果cur的下一个节点的值(val)是 目标 val
                cur.next = cur.next.next
     # 让当前cur的指针(cur.next)  等于 下一个节点(cur.next)的指针 即 cur.next.next
            else:
                cur = cur.next               # 没找到目标值 就将cur往后移一个节点
        return dummy_head.next              # 返回头节点 

next 指向的是节点 ,节点包含两部分(重要)

单链表最后指向的是None

cur 是节点 ,cur.next 是下一个节点 ,cur.next.val是下一个节点的数值,

当前节点储存的是当前的数值和下一个节点的地址。

三、设计链表

  • 疑问

为什么在构建虚拟头节点后(self.head=Node()),虚拟头节点就指向头节点(self.head.next)。在addAtHead 函数中 就默认了 这一事实

以下构造的函数都默认了这一事实

class Node(object):  # 定义节点
    def __init__(self,val=0,next = None):
        self.val = val
        self.next = next

class MyLinkedList(object):
    def __init__(self):
        self.head = Node()   # 创建虚拟头节点
        self.size = 0       # 最开始的数量为0 本身是空的 后面会更新
# 获取链表中第 index 个节点的值。如果索引无效,则返回-1
    def get(self, index: int) -> int:
        cur = self.head.next  # 创建一个游标指针 可以移动
        if index < 0 or index >= self.size:        # 需要先判断是否为无效索引
            return -1
        while (index):       # 循环
            cur = cur.next   # 让指针移动
            index -= 1  

        return cur.val       # 返回节点的值

# 在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
    def addAtHead(self, val: int) -> None:
        new_node = Node(val)                        # 创建新的节点
        new_node.next = self.head.next             # 让新节点指向 虚拟头节点的下一个节点(头节点)
        self.head.next = new_node                  # 让虚拟头节点 指向新的节点
        self.size += 1                             # size + 1

# 将值为 val 的节点追加到链表的最后一个元素。
    def addAtTail(self, val: int) -> None:
        new_node = Node(val)                        # 创建新的节点
        cur = self.head                             # 创建一个游标指针 可以移动
        while (cur.next):
            cur = cur.next                          # 让指针移动
        cur.next = new_node                         # 此时cur对应最后一个节点,让其指向新节点 
        self.size += 1                             
"""
在链表中的第 index 个节点之前添加值为 val  的节点。
如果 index 等于链表的长度,则该节点将附加到链表的末尾。
如果 index 大于链表长度,则不会插入节点。
如果index小于0,则在头部插入节点。
"""

    def addAtIndex(self, index: int, val: int) -> None:
        if index > self.size:        
            return
        elif index < 0 :            # 根据题目要求设置判断条件,利用之前写好的函数
            self.addAtHead(val)
            return
        elif index == self.size:
            self.addAtTail(val)
            return
        else:                               # 正常情况
            new_node = Node(val)            # 创建新节点
            cur = self.head                 # 创建一个游标指针 可以移动
            while (index):
                cur = cur.next
                index -=1                 # 循环结束后,cur对应是index的前一个节点
            new_node.next = cur.next      # 让新节点指向 cur的下一个节点 即 index节点 
            cur.next = new_node           # 让cur的下一个节点指向 新节点
            self.size += 1
# 如果索引 index 有效,则删除链表中的第 index 个节点
    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >= self.size:  # 判断
            return
        cur = self.head 
        while (index):
            cur = cur.next
            index -= 1                    # 循环结束后,cur对应 index 的前一个节点
        cur.next = cur.next.next         # 让cur的下一个节点指向index的下一个,即跳过了index
        self.size -= 1                    # 长度减一

四、反转链表

题目

思路

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head
        pre = None            # 由于要反转,头变尾,pre 需要指向 None pre为前指针 在head之前。最初
        while(cur!=None):     # 正向循环时,cur为None 结束循环
        # 反转方法
            tem = cur.next    # 需要先保存cur的下一个节点,不然会丢失后面的节点
            cur.next = pre    # 让cur指向pre(前) 箭头方向就反转过来了
            pre = cur         # 然后让双指针往前,pre挪到下一个节点
            cur = tem         # cur挪到下一个节点 tem保存了cur的下一个节点
        return pre
  • 重难点

需要判断循环终止的条件,或者明确cur或者pre停在哪一个节点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值