DAY3 代码随想录 链表1

链表基础理论

链表是通过指针串联在一起的线性结构,每个结点由两部分组成——数据域和指针域(存放指向下一节点的指针)最后一个节点的指针域指向Null(空指针)

  • 单链表中的指针域只能指向节点的下一个节点。双链表的每个节点有两个指针域分别指向上一个节点和下一个节点。
  • 即单链表只能向后查询,双链表可以向前向后查询。
  • 循环链表首尾相连,可以解决约瑟夫环问题
    链表在内存中并不是连续分布的,而是散乱分布在内存中的某地之上,分配机制取决于操作系统的内存管理。
    链表的定义(含C++和Python两种
//单链表
struct ListNode{
	int val; //节点上的存储元素
	ListNode *next;  //指向下一节点的指针
	ListNode(int x) : val(x), next(NULL) {} //节点的构造函数
	};
class ListNode:
	def __init__(self,val = 0, next = None):
		self.val = val
		self.next = next

性能分析

在这里插入图片描述

  • 数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。

  • 链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。

203 移除链表元素

我的错误思路:这个思路主要错在没有考虑head节点对应的值也是目标值的情况

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        cur = head
        while cur:
            if cur.next.val == val:
                cur.next = cur.next.next
            cur = cur.next
        return head

正确思路:首先我们需要设置一个永远指向head的指针,以应对当head节点的值也是目标值需要删掉的情况。
在链表中,当我们需要删除当前节点时需要使用它的上一节点的next使其指向当前节点的下一节点。
因此我们设置cur来遍历整个链表,设置pre作为cur的上一节点。

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        # 设置一个永远指向head的指针
        headpre = ListNode()
        headpre.next = head
        # cur节点用于遍历链表
        cur = head
        # pre节点始终指向cur节点的前一个节点,方便删除节点
        pre = headpre
        while cur:
            if cur.val == val:
                pre.next = cur.next
                cur = cur.next
            else: #此处cur和pre顺序随意,都可以
                cur = cur.next
                pre = pre.next
        return headpre.next

思想一致,但更简练一些,这种写法值得学习一下

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        #添加辅助的虚拟节点 令其指向头节点
        prehead = ListNode(next = head)
        cur = prehead
        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return prehead.next

707 设计链表

这道题我踩了很多坑,首先我们在设计每个函数的时候一定要明确它的极端情况的边界条件,否则很容易报错。我们可以边写边画每个流程,就能够更直观清楚的防止这种错误的发生。

# 首先定义结点
class ListNode:
    def __init__(self,val = 0, next = None):
        self.val = val
        self.next = next

class MyLinkedList:
    def __init__(self):
        # 通过创建虚拟头结点进行操作
        self.head = ListNode()
        # 记录当前结点数量
        self.size = 0

    def get(self, index: int) -> int:
        # 判断极端条件
        # 注意此处index=self.size时下标无效
        if index < 0 or index >= self.size:
            return -1
        cur = self.head.next
        for _ in range(index):
            cur = cur.next
        return cur.val

    # addAtHead和addAtTail本质上都是addAtIndex的特殊情况,可以直接调用addAtIndex
    def addAtHead(self, val: int) -> None:
        self.addAtIndex(0,val)

    def addAtTail(self, val: int) -> None:
        self.addAtIndex(self.size,val)

    def addAtIndex(self, index: int, val: int) -> None:
        # 考虑极端情况
        # 注意此处index = self.size时意味着将值为val的结点加到链表的尾部,因此此处条件需要是index>self.size
        if index < 0 or index > self.size:
            return
        # 注意此处不要使用pre=self.head.next,否则循环最后pre将会有None的情况,最后pre.next不成立了
        pre = self.head
        for _ in range(index):
            pre = pre.next
        pre.next = ListNode(val,pre.next)
        # 注意我们的方法addAtHead和addAtTail都是基于addAtIndex的特殊情况,因此不要在addAtHead和addAtTail中对self.size进行+1的操作
        self.size+=1

    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >=self.size:
            return
        pre = self.head
        for _ in range(index):
            pre = pre.next
        t = pre.next
        pre.next = t.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

反转链表

主要用到了双指针的思想,设置了两个指针cur和pre,cur遍历整个链表,并将其next指针转移,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: ListNode) -> ListNode:
        # 定义一个cur指向头节点,遍历整个链表
        cur = head
        pre = None
        while cur:
            tmp = cur.next
            cur.next = pre
            # 更新pre和cur指针
            pre = cur #这步很容易忽略!!!
            cur = tmp
        return 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: ListNode) -> ListNode:
        return self.reverse(head,None)
    def reverse(self,cur:ListNode,pre:ListNode) -> ListNode:
        if cur == None:
            return pre
        tmp = cur.next
        cur.next = pre
        return self.reverse(tmp,cur)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值