labuladong刷题day2(继续链表练习题)

Q1题目链接https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/

leetcode 82

看到题目的第一思路:

快慢指针的技巧

代码随想录之后的想法和总结:

Q:三层循环怎么理解?

A:外层 while 是遍历,if 是判断是否重复,内层 while 是跳过一整段重复的节点。

  • q快指针,负责扫描原链表,跳过重复节点,寻找“下一个有效节点”。

  • p慢指针,负责构造新的链表,只在遇到“非重复节点”时才向前移动。

只有当 q 当前指向的是不重复节点时,才会把 q 加到结果链表中,同时 p 才会往前走一步。

如果 q 指向的是重复段(比如好几个 3),p 就保持不动,直到 q 跳过所有 3

时间复杂度以及空间复杂度:

时间复杂度;O(n), n是链表中的节点数

🔍 为什么是 O(n)

  • 每个节点最多被访问两次:

    1. 第一次被 q(快指针)访问(扫描的时候)

    2. 如果是唯一值,还会被 p(慢指针)接入新链表

  • 虽然有一个嵌套的 while 循环:

while q.next is not None and q.val == q.next.val:
    q = q.next

但这个并不是 O(n²),因为:

  • 整个链表中每个节点最多被 q 访问一次

  • 所以总共最多进行 n 次移动

空间复杂度是 O(1)(常数空间):

  • 只用了 dummy, p, q 这几个指针

  • 没有用栈(不像递归法),也没有新建额外链表结构(不像分解法)


Q2题目链接https://leetcode.com/problems/ugly-number-ii/

leetcode 264  丑数

看到题目的第一思路:

首先理解 什么是丑数,然后本题,看似是数学题,其实是合并多个链表的问题

代码随想录之后的想法和总结:

首先参考第21题的思路:合并多个有序链表,然后理解丑数的概念并且通过数学公式把有序链表的构造写出来,再通过双指针算法进行合并即可。

你可以这样理解整个过程:

  • ugly 是一条主线:我们想填满它,得到第 n 个丑数。

  • p2, p3, p5 是三条支线:分别从已生成的丑数乘 2、乘 3、乘 5,生成候选值。

  • 每次都选最小值(像归并排序一样),并更新使用了的那一支的指针。

时间复杂度以及空间复杂度:


Q3题目链接https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/

leetcode 378

看到题目的第一思路:

和之前合并链表类似,但是那个题是用优先级队列里的二叉堆,这个就是单纯的链表组成的优先级队列

代码随想录之后的想法和总结:

1 学会怎么用矩阵存储链表中的元素,并且和优先级队列相结合,

这个三元组的含义是:

  • matrix[i][j]:元素值(❗这是排序关键字

  • i:所在的行

  • j:所在的列

(matrix[i][0],i,0))

2 怎么用put和get来添加和取出(删除)优先级队列里的最小元素来控制队列元素组成

优先队列(PriorityQueue)默认比较的是元组的第一个元素

所以在入队/出队时,比较的是 matrix[i][j],也就是数值本身

get用来从优先队列中取出并删除当前优先级最高(也就是值最小)的元素

put() —— 放入队列

  • 作用:往队列里添加一个元素

  • PriorityQueue 中,它会自动按照**优先级(默认是元组的第一个值)**插入到正确的位置。

时间复杂度以及空间复杂度:

初始化队列(put 每一行的第一个元素):

  • 一共 put 了 n 个元素(n 行)

  • 每次 put() 操作在 PriorityQueue 中的复杂度是 O(log n)

➡️ 所以初始化是:O(n log n)

主循环(执行 k 次 get & put):

  • 最多执行 k 次(我们要找第 k 小的元素)

  • 每次最多进行一次 get() 和一次 put(),每次都是 O(log n)

➡️ 循环总体是:O(k log n)

所以-O(n log n) + O(k log n) = O((n + k) log n)

空间:

  • 优先队列最多存储 n 个元素(每行最多放一个在队列里)

  • 所以空间复杂度为:O(n)


Q4题目链接https://leetcode.com/problems/find-k-pairs-with-smallest-sums/

leetcode 373

看到题目的第一思路:

和上题类似,都是先生成三个链表,然后按照升序合并(也参考第23题)

代码随想录之后的想法和总结:

每个元素是一个四元组 (sum, num1, num2, idx)

  • sum = num1[i] + num2[j],存储当前数对的和。

  • num1num2 是当前正在考虑的两个数,分别来自 nums1nums2

  • idxnums2 中元素的索引,记录当前 num2nums2 中的哪个元素。

每次从队列中取出一个数对后,我们要执行两件事:

  1. 减小 k:每取出一个最小的数对,就找到了一个有效的结果,因此 k 减少。

  2. 插入下一个数对:对于当前取出的数对 num1num2,我们尝试将 nums1[i]nums2[idx+1] 组合成新的数对,并将其插入队列。这样就保证了下一个最小的数对一定会被找到,因为队列会自动按和的大小排序。

Q: 为什么循环 k 次就能找到最小的 k 对数

  • 每次从队列中取出的是当前未处理的最小和,直到我们完成 k 次操作。

  • 由于每次从队列中取出的数对都是当前最小的(这是优先队列保证的),所以循环 k 次就能找到最小的 k 个数对。

时间复杂度以及空间复杂度:

  • 时间复杂度

    • 初始插入优先队列的时间复杂度是 O(n),其中 nnums1 的长度。

    • 每次从队列中取出最小的元素和插入新元素的时间复杂度是 O(log n)。因为队列中最多有 n 个元素,每次操作的时间复杂度为 O(log n)

    • 总共进行 k 次操作,所以总时间复杂度是 O(k log n)

  • 空间复杂度

    • 空间复杂度是 O(n),因为优先队列最多保存 n 个元素。


Q5:  https://leetcode.com/problems/add-two-numbers/

leetcode 2 两数之和

看到题目的第一思路:

计算的原理 以及处理进位 储存数字 需要复习

利用双指针:p1p2 分别指向 l1l2 链表的当前节点,模拟加法过程中的逐位求和。

代码随想录之后的想法和总结:

Q: 遍历条件 while p1 is not None or p2 is not None or carry > 0: 让我们能够:

  • 继续遍历未遍历完的链表。

  • 处理因为加法产生的进位。 确保所有情况都被正确处理,直到加法完全结束。

Q: 如何处理进位?

carry = val // 10 计算新的进位,而 val = val % 10 保证当前位的结果是个位数。

时间复杂度以及空间复杂度:

时间: O(max(n1,n2)), n1,n2 是链表l1,l2的长度

Q:为什么是max(n1,n2),因为要处理以下两种情况

链表长度不相等的情况:

  • 假设链表 l1 的长度为 n1,链表 l2 的长度为 n2。在加法过程中,可能会有一个链表更长,另一个链表遍历完了

进位的情况:

  • 如果两个链表的长度相同并且没有进位,程序会在 n1n2 次循环内结束。如果有进位,额外的一个节点会在最后加入,但这并不影响主要的时间复杂度

空间:O(max(n1,n2))

    • 我们最终会生成一个新的链表来存储结果。这个新链表的长度最多为 max(n1, n2) + 1(因为可能有一个额外的进位)。

    • 所以,结果链表所占的空间是 O(max(n1, n2))

Q6: https://leetcode.com/problems/add-two-numbers-ii/

leetcode 445 两数相加

看到题目的第一思路:

本题的主要难点在于链表中数位的顺序与我们做加法的顺序是相反的,为了逆序处理所有数位,我们可以使用栈:把所有数字压入栈中,再依次取出相加。计算过程中需要注意进位的情况。

代码随想录之后的想法和总结:

总结:

  • 链表中的数位顺序与加法顺序相反,因为链表按照高位到低位存储数字,而加法是从低位到高位进行的。

  • 解决方案: 可以通过翻转链表或使用栈来调整顺序,以便正确地从低位开始加。

  • 使用栈的方法避免了修改链表结构,直接通过栈的后进先出的特性来实现逐位加法。

那么就有了两种思路:
思路一:反转链表。
思路二:使用栈保存链表中的数字。(栈是先进后出的,所以起到了翻转功能)

题目中说了:不能修改输入的链表。所以只能用思路二「栈」来解决。

Q:最后dummy的操作起什么作用?

使用 虚拟头结点(dummy),我们能够简化链表操作,将每次计算得到的结果节点插入到链表头部,从而避免了在头节点插入时的复杂情况。

时间复杂度以及空间复杂度:

  • 时间复杂度O(n1 + n2),其中 n1n2 是链表 l1l2 的长度。我们需要遍历两个链表并逐位加法。

  • 空间复杂度O(n1 + n2),主要由栈存储链表元素和结果链表的存储空间决定。

今日收获,学习时长:

总结
「求加法」系列题目都不难,其实就是 「列竖式」 计算。
需要注意的是:
while循环结束条件;
遍历两个「加数」不要越界;
进位。
链表在插入的时候如何进行反转

⚠️对于逆序处理首先想到栈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值