学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

news2024/9/19 10:44:31

文章目录

    • 删除排序链表中的重复元素
      • 我的思路
        • 解法一:循环
        • 解法二:递归
      • 网上思路
    • 删除排序链表中的重复元素 II
      • 我的思路
      • 网上思路
    • 总结

删除排序链表中的重复元素

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

图一
在这里插入图片描述

图二
在这里插入图片描述

示例 1:(图一)
输入:head = [1,1,2]
输出:[1,2]

示例 2:(图二)
输入:head = [1,1,2,3,3]
输出:[1,2,3]

我的思路
两个思路,一个是循环,一个是递归
网上思路
双指针

我的思路

解法一:循环
var deleteDuplicates = function(head) {
  let current = head;
  while (current && current.next) {
    if (current.val === current.next.val) {
      current.next = current.next.next; 
    } else {
      current = current.next;
    }
  }
  return head;
};

讲解

  1. 初始化指针:创建一个指针 current 指向链表的头节点。
  2. 遍历链表:遍历链表直到 current.next 为空。
  3. 检查重复:如果当前节点 current 的值与下一个节点 current.next 的值相同,则跳过下一个节点,即将 current.next 设置为 current.next.next
  4. 继续遍历:如果当前节点 current 的值与下一个节点 current.next 的值不同,则将 current 指针移动到下一个节点。
  5. 返回结果:遍历完成后返回链表的头节点。
解法二:递归
var deleteDuplicates = function (head) {
    if (head === null || head.next === null) return head;
    if (head.next.val === head.val) {
        head.next = head.next.next;
        return deleteDuplicates(head);
    } else {
        head.next = deleteDuplicates(head.next);
        return head;
    }
};

讲解

  1. 如果链表为空(head === null) 或只有一个节点 (head.next === null),则返回头节点,因为没有重复节点需要删除。
  2. 如果当前节点的值与下一个节点的值相同**(head.next.val === head.val)**,则说明存在重复节点。
  3. 通过 head.next = head.next.next,我们将当前节点的 next 指向下一个节点的下一个节点,从而跳过了重复节点。
  4. 然后递归调用 deleteDuplicates(head),继续检查当前节点**(head)**的下一个节点。
  5. 如果当前节点的值与下一个节点的值不相同,说明没有重复节点。
  6. 递归调用 deleteDuplicates(head.next) 处理下一个节点,并将返回的结果赋值给 head.next,以确保链表的结构保持正确。

网上思路

var deleteDuplicates = function (head) {
    if (!head) return head;
    let prev = head;
    let current = head.next;
    while (current) {
        if (current.val === prev.val) {
            prev.next = current.next;
        } else {
            prev = current;
        }
        current = current.next;
    }
    return head;
};

讲解

  1. 初始化指针:
    prev 指向链表的头节点。
    current 指向头节点的下一个节点。
  2. 遍历链表:
    使用 while (current) 来遍历整个链表
  3. 检查重复:
    如果 current.val 和 prev.val 相同,说明存在重复。
    prev.next = current.next:通过调整 prevnext 指针,跳过重复的节点。
  4. 移动指针:
    如果当前节点和前一个节点的值不同,则移动 prev 指针到当前节点。
    无论是否有重复,current 指针始终向前移动。

删除排序链表中的重复元素 II

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

图三
在这里插入图片描述

图四
在这里插入图片描述

示例 1:(图三)
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]

示例 2:(图四)
输入:head = [1,1,1,2,3]
输出:[2,3]

我的思路
双指针
网上思路
递归

我的思路

var deleteDuplicates = function (head) {
    let dummy = new ListNode(0, head);
    let prev = dummy;
    let curr = head;
    while (curr && curr.next) {
        if (curr.val === curr.next.val) {
            while (curr.next && curr.val === curr.next.val) {
                curr = curr.next;
            }
            prev.next = curr.next;
        } else {
            prev = prev.next;
        }
        curr = curr.next;
    }
    return dummy.next;
};

讲解

  1. 创建哑节点:为了方便处理头节点可能被删除的情况,我们可以在链表前面添加一个哑节点。
  2. 初始化指针:创建一个指针 prev 指向哑节点,创建一个指针 curr 指向链表的头节点。
  3. 遍历链表:遍历链表直到 curr 到达末尾。
  4. 检查重复:如果当前节点 curr 的值与下一个节点 curr.next 的值相同,则继续向前遍历直到找到一个不同的节点。
  5. 连接不同节点:一旦找到不同的节点,将 prev.next 设置为这个不同的节点。
  6. 更新指针:如果没有重复节点,则将 prevcurr 都移动到下一个节点。
  7. 返回结果:遍历完成后返回哑节点的下一个节点作为新的头节点。

网上思路

var deleteDuplicates = function (head) {
    if (!head || !head.next) return head
    if (head.val === head.next.val) {
        while (head.next && head.next.val === head.val) head.next = head.next.next
        return deleteDuplicates(head.next)
    } else {
        head.next = deleteDuplicates(head.next)
    }
    return head
};

讲解

  1. 基本情况检查:
    if (!head || !head.next) return head:如果链表为空**(head 为 null)或者只有一个节点(head.next 为 null)**,则直接返回 head。这是递归的基本情况,表示链表已经处理完成。
  2. 检查当前节点与下一个节点的值:
    if (head.val === head.next.val):检查当前节点的值是否与下一个节点的值相同。如果相同,说明存在重复节点。
  3. 跳过重复节点:
    while (head.next && head.next.val === head.val) head.next = head.next.next:使用 while 循环,继续跳过所有与当前节点值相同的节点, 直到找到一个不同的节点或到达链表末尾。
  4. 递归调用:
    return deleteDuplicates(head.next):在跳过所有重复节点后,递归调用 deleteDuplicates 处理下一个节点,并返回处理后的链表。
  5. 处理不同的节点:
    else { head.next = deleteDuplicates(head.next) }:如果当前节点的值与下一个节点的值不同,递归调用 deleteDuplicates 处理下一个节点,并将返回的结果赋值给 head.next
  6. 返回处理后的头节点:
    return head:最后,返回处理后的链表头节点。

总结

链表的题目写了这么多天,好像都可以用递归来解题,今天尝试了一下,还是不错的,后面可以再多尝试尝试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2116235.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件质量保障:故障演练介绍

目录 背景:架构变化带来的问题 什么是故障演练 为什么需要故障演练 故障演练场景有哪些 不同演练类型和目标 如何对工具进行评估 功能评测项 告警评测项 观测指标评测项 总结 背景:架构变化带来的问题 随着架构越来越复杂、应用越来越多样&…

外卖霸王餐对接接口为用户提供了哪些好处?

外卖霸王餐对接接口为用户提供了多种好处,以下是一些主要优势: 免费或低成本的美食体验:用户可以通过霸王餐活动免费或以非常低的价格尝试不同的餐厅和菜品。发现新餐厅和菜品:霸王餐活动可以帮助用户发现新的餐厅和他们可能感兴趣…

【C/C++IO流汇总】C/C++IO流以及系统调用open/read/write等详解

IO流学习分享 1、C中文件IO使用1.1、文件函数1.2、文件的使用方式1.3、文件的读写函数1.4、示例1.4.1、fgetc()函数1.4.2、getc()函数1.4.3、fputc()函数1.4.4、putc()函数1.4.5、fgets()函数1.4.6、fputs()函数1.4.7、fscanf()函数1.4.8、fprintf()函数 1.5、fread()函数1.5.1…

stm32之SPI通信协议

文章目录 前言一、SPI通信协议1.1 SPI简介1.2 SPI通信特点1.3 SPI与I2C对比 二、SPI硬件电路三、SPI通信原理四、SPI时序单元4.1 起始和终止条件4.2 交换一个字节(模式1)4.3 交换一个字节(模式0)4.4 交换一个字节(模式2和3) 五、SPI时序5.1 发送指令5.2 指定地址写5.3 指定地址…

软件部署-Docker容器化技术

开始前的环境说明 VMware 17 Pro Centos release 7.9.2009(防火墙已关闭) Docker 26.1.4 Docker镜像加速器配置:"https://do.nark.eu.org", "https://dc.j8.work", "https://docker.m.daocloud.io", "https://dockerproxy.com", &…

PDF 软件如何帮助您编辑、转换和保护文件。

如何找到最好的 PDF 编辑器。 无论您是在为您的企业寻找更高效的 PDF 解决方案,还是尝试组织和编辑主文档,PDF 编辑器都可以在一个地方提供您需要的所有工具。市面上有很多 PDF 编辑器 — 在决定哪个最适合您时,请考虑这些因素。 1. 确定您的…

十一、MySQL高级—工具和技巧拾遗~视图 VIEW(4)

🌻🌻 目录 一、是什么二、作用三、适用场景四、语法五、注意事项(适用5.5) 文章大纲 👇👇 一、是什么 将一段查询sql封装为一个虚拟的表。 这个虚拟表只保存了sql逻辑,不会保存任何查询结果。 二、作用 1、封装复杂sql…

开放式系统互连(OSI)模型的实际意义

0 前言 开放式系统互连(OSI,Open Systems Interconnection)模型,由国际标准化组织(ISO)在1984年提出,目的是为了促进不同厂商生产的网络设备之间的互操作性。 定义了一种在层之间进行协议实现…

EVO进行轨迹评估

EVO进行轨迹评估 文章目录 EVO进行轨迹评估1 前言1.1 轨迹对齐1.2 尺度变换1.3 绝对轨迹误差ATE和相对轨迹误差RTE1.4 绝对姿态误差APE和相对姿态误差RPE 2 安装evo2.1 evo安装2.2 相关报错2.2.1 版本不兼容问题2.2.2 解决PATH警告 2.3 测试 3 evo指令3.1 evo_traj3.2 evo_ape3…

深入理解单元测试

荐语 本文要介绍的是 2020 年 O’Reilly 出版的书籍 Unit Testing Principles, Practices, and Patterns,一本在豆瓣评分高达 9.9 的好书。 作为一名软件开发工程师,你应该对单元测试(unit test)很熟悉,但单元测试的目…

Scratch中秋节:中秋节赏月

小虎鲸Scratch资源站-免费Scratch作品源码,素材,教程分享平台! 作品推荐:中秋节赏月 | 一起享受中秋的美好时光 中秋佳节即将来临,一起感受传统节日的温馨氛围吧!小虎鲸Scratch资源站最新推出的节日作品《中秋节赏月》,将带你走进…

CTK框架(四): 插件编写

目录 1.生成插件 1.1.环境说明 1.2.服务类,纯虚类,提供接口 1.3.实现插件类,实现纯虚函数 1.4.激活插件,加入ctk框架的生命周期中 1.5.添加资源文件 1.6..pro文件 2.使用此插件 3.总结 1.生成插件 1.1.环境说明 编译ct…

【论文精读】 | 用于时间序列预测的通道对齐坚固的混合Transformer

文章目录 0、摘要1、介绍2、相关工作2.1 用于时间序列预测的Transformers2.2 用于时间序列预测的 RNN、MLP 和 CNN 模型 3、模型结构3.1 令牌化3.2 CARD 注意力胜过token3.3 CARD 注意力胜过渠道3.4 token 混合模块 4、基于信号衰减的损失函数5、实验5.1 长期预测5.2 基于重建的…

STM32——串口通信(发送/接收数据与中断函数应用)

文章目录 通信:串口通信简介:1.双工/单工:2.同步/异步:3.电平:电平标准: 串口参数以及数据帧时序:数据帧:1.波特率和比特率:例:无校验,1位停止位 …

B: 小球反弹

目录 一: 二: 三: 四: 一:问题描述 有一长方形,长为343720 单位长度,宽为233333 单位长度。在其内部左上角顶点有一小球(无视其体积),其初速度如图所示且…

【MySQL】MySQL中表的增删改查——(基础篇)(超详解)

前言: 🌟🌟本期讲解关于MySQL中CDUD的基础操作,希望能帮到屏幕前的你。 🌈上期博客在这里:http://t.csdnimg.cn/fNldO 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 目录 …

Python Flask_APScheduler定时任务的正确(最佳)使用

描述 APScheduler基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能。最近使用Flask框架使用Flask_APScheduler来做定时任务,在使用过程当中也遇到很多问题,例如在定时任务调用的方法中需要用到flask的app.app_context()时&#…

Transformer预测 | 基于Transformer心率时间序列预测(tensorflow)

效果一览 基本介绍 Transformer预测 | 基于Transformer心率时间序列预测(tensorflow) 程序设计 import pandas as pd from pandas.plotting import lag_plot from statsmodels.graphics

暴雨AMD,一起更YES

9月6日,暴雨信息联合AMD举办了“创新驱动 智能未来——2024年行业技术与应用分享会”。在这里,我们与行业领袖、技术专家们一起,深入探讨AI技术的前沿技术动态,洞悉高性能计算的发展趋势,在思维的碰撞和智慧的交融中&a…

BERT 论文逐段精读【论文精读】

BERT: 近 3 年 NLP 最火 CV: 大数据集上的训练好的 NN 模型,提升 CV 任务的性能 —— ImageNet 的 CNN 模型 NLP: BERT 简化了 NLP 任务的训练,提升了 NLP 任务的性能 BERT 如何站在巨人的肩膀上的?使用了哪些 NLP 已有的技术和思想&#xff…