【算法】移除链表元素与反转链表

目录

前言

移除链表元素

题目描述

解题思路

代码

反转链表

题目描述

解题思路

代码

总结


前言

本文主要讲解力扣203题移除链表元素和206题反转链表的解题思路和代码实现

对于链表的操作重点在于指针的使用,这两道题都需要用到指针,不过一个是单指针,一个是双指针,其中有一些异同点,因此放在一起分析

下文会先分别讲解这两道题,最后放在一起总结

移除链表元素

题目描述

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

示例1

输入: head = 1,2,6,3,4,5,6, val = 6
输出:1,2,3,4,5

示例 2

输入: head = \[\], val = 1
输出:\[\]

示例 3

输入: head = 7,7,7,7, val = 7
输出:\[\]

解题思路

这道题本身思路很简单,用指针遍历链表中的每一个节点

(1)若节点值不等于val则什么也不用做,改变指针指向下一个节点即可

(2)若节点值等于val,需要控制节点的 next 指针跳过紧挨的下一个节点

需要注意的是,用单指针就可以解决而不用用双指针

若用双指针,p指向当前节点,pnext指向下一个节点,则pnext.val==val时:

p.next=pnext.next,pnext=pnext.next

若用单指针,p指向某一节点,则p.next.val==val时:

p.next=p.next.next即可

显然用单指针是更高效的

另外,为了避免判断头节点是否为空,以及头节点是否需要删除等复杂的异常情况,设计一个虚头节点,就可以实现操作的统一,具体实现代码如下

代码

python 复制代码
from typing import Optional

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]:
        virtualNode = ListNode(0, head)#虚的头节点
        p = virtualNode
        while p.next:
            if p.next.val == val:
                p.next = p.next.next
            else:
                p = p.next
        return virtualNode.next

反转链表

题目描述

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表

示例1

输入: head = 1,2,3,4,5
输出:5,4,3,2,1

示例2

输入: head = \[\]
输出:\[\]

解题思路

这道题就相对复杂一些,我们很容易想到用双指针 解决,但难点在于双指针的变化顺序,如果处理不当就会出现无法继续遍历或死循环等问题

这里给出一个例子,若p指向某节点,pnext指向下一个节点,现在要将pnext的指向反转,如果这样写:

pnext.next=p

p=pnext

然后就会出现一个问题:pnext的指向是反转了,但是发现无法指向下一个新节点了,因为pnext的指向已经反转,无法用pnext=pnext.next,如果真这样写了就会死循环,在两个节点之间出不来

当然,用三指针可以很容易的解决这个问题,若pre指向上一个节点,p指向当前节点,pnext指向下一个节点,则:

p.next=pre

pre=p

p=pnext

pnext=pnext.next(因为pnext的指向没有变,变的是p的指向)

不过如果用三指针,力扣中测评时会内存超限...

因此我们只能改进双指针法:在改变pnext指向之前先用一个变量保存一下下一个节点的地址,最后让pnext指向这个保存好的地址

具体实现代码如下

代码

python 复制代码
from typing import Optional

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]:
        p, pnext = None, head
        while pnext:
            temp = pnext.next #暂存下一个节点地址,要不然指针改了后就不能到达新节点了
            pnext.next = p
            p = pnext
            pnext = temp
        return p

总结

对比这两道题目可以发现,最主要的区别是链表的指向是否改变

在第一道题中,指向没有改变,则不管用多少层p.next.next...都是没有关系的,都能正确找到想要指向的新节点

而第二道题中,因为指向发生了改变,用p.next.next就会循环回来,此时不得不用另一个指针保存next地址,以找到下一个新节点

相关推荐
GreenTea6 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
Bode_20026 小时前
多资源规划(含生产调度、库存管理及产能规划)的创新优化算法
算法·调度
Logic1017 小时前
C语言/数据结构位运算题解:异或XOR找出蛋糕订单中的“VIP独特口味“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
土司大王7 小时前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
微三云生态系统架构师-彭丹8 小时前
远方好物S2B2C系统架构:一级分销与保证金托管的合规技术实现
人工智能·算法
颜颜yan_8 小时前
ESP-IDF 鸿蒙 PC 适配全记录:打通 Python、构建工具链与 ESP32-P4 固件生成
python·华为·harmonyos
言乐68 小时前
Python加速器4跨境网络加速器
运维·服务器·开发语言·网络·python
土司大王8 小时前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
weixin_440730508 小时前
线程02-并发串行-互斥锁-Semaphore-Event
python·thread
Logic1018 小时前
C语言/数据结构位运算题解:异或XOR找出飞行棋中的“独特颜色棋子“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质