LeetCode算法题合集—链表篇

2023-11-09

链表基础算法题

链表的定义(java)

//单链表的定义
public class ListNode{
	int val;
	ListNode next;	//指向下一节点
	ListNode(){};	//无参构造
	ListNode(int val){ this.val=val; }
	ListNode(int val,ListNode next){ this.val=val; this.next=next; }
}

1.移除链表元素

https://leetcode-cn.com/problems/remove-linked-list-elements/
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:
输入:head = [7,7,7,7], val = 7
输出:[]

方法一:直接法—迭代
删除头结点时另做考虑

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        while(head!=null && head.val==val){
            head=head.next;     //若满足条件,则移动头节点的位置
        }
        if(head==null) return head;
        ListNode first = head;  //保存头节点的位置
        while(head.next!=null){
            if(head.next.val==val){
                head.next=head.next.next;
            }else{
                head=head.next;
            }
        }
        return first;
    }
}
//时间复杂度: O(n)
//空间复杂度: O(1)

方法二:虚拟头节点(常用)
设置一个虚拟头结点,不需要另外考虑头节点,这样原链表的所有节点就都可以按照统一的方式进行移除了

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //虚拟结点,指向下一个结点是head头节点
        ListNode dummy = new ListNode(-1,head); 
        ListNode prev=dummy;    //借用其他结点进行删除,保证dummy.next指向头节点
        while(prev.next!=null){
            if(prev.next.val==val){
                prev.next=prev.next.next;
            }else{
                prev=prev.next;
            }
        }
        return dummy.next;
    }
}
//时间复杂度: O(n)
//空间复杂度: O(1)

方法三:递归
递归的终止条件是head为空,此时直接返回head
head 不为空时,递归地进行删除操作,然后判断head 的节点值是否等于val 并决定是否要删除head

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;	//退出递归
        }
        head.next = removeElements(head.next, val);	//下一个结点交给递归处理
        return head.val == val ? head.next : head;	//保证当前节点满足条件
    }
}
//时间复杂度: O(n)
//空间复杂度: O(n) 其中n是链表的长度。空间复杂度主要取决于递归调用栈,最多不会超过n层

2.设计链表

https://leetcode-cn.com/problems/design-linked-list/
设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:valnext。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

方法一:单链表法
先设计 addAtIndex,因为伪头的关系 addAtHead 和 addAtTail 可以使用 addAtIndex 来完成。

public class ListNode {
  int val;
  ListNode next;
  ListNode(int x) { val = x; }
}

class MyLinkedList {

    int size;   //链表大小
    ListNode head;  //虚拟头节点

    public MyLinkedList() {
        size = 0;
        head = new ListNode(0);
    }
   
    /*+++++++++++++++++方法实现++++++++++++++++++*/
    
    //对应下标插入新节点
    public void addAtIndex(int index, int val) {
        if (index > size) return;
        if (index < 0) index = 0;
        ListNode node = new ListNode(val);
        ListNode prev = head;
        while(index-- > 0) prev = prev.next;
        node.next = prev.next;
        prev.next = node;
        size++;
    }
	//头部插入新节点
    public void addAtHead(int val) {
        addAtIndex(0,val);
    }
    //尾部插入新节点
    public void addAtTail(int val) {
        addAtIndex(size,val);
    }
    //删除对应下标的节点
    public void deleteAtIndex(int index) {
        if(index>=size||index<0) return;
        ListNode prev=head;
        while(index-- > 0) prev = prev.next;
        prev.next = prev.next.next;     //删除节点prev.next
        size--;
    }
	//获取对应下标的节点值
    public int get(int index) {
        if(index>=size||index<0) return-1;
        ListNode prev=head;
        while(index-- >= 0) prev = prev.next;
        return prev.val;
    }
}

3.反转链表

https://leetcode-cn.com/problems/reverse-linked-list/
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

题解:
假设存在链表 1→2→3→∅,我们想要把它改成 ∅←1←2←3。
方法一:迭代
在遍历列表时,将当前节点的 next指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针tmp来存储下一个节点。不要忘记在最后返回新的头引用!
在这里插入图片描述

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre=null;
        ListNode curr=head;
        while(curr!=null){
            ListNode tmp=curr.next; // 保存下一个节点
            curr.next=pre;  //指向反向
            pre=curr;
            curr=tmp;
        }
        return pre;     //返回新的头节点
    }
}
//时间复杂度: O(n)
//空间复杂度: O(1) 

方法二:递归
n1—>n2—>....—>nk—>n2

class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode p = reverseList(head.next);
        head.next.next = head;  //指向反转 head.next-->head
        head.next = null;       // 当前head-->null
        return p;
    }
}
//时间复杂度: O(n)
//空间复杂度: O(n) 

4.两两交换链表中的节点

https://leetcode-cn.com/problems/swap-nodes-in-pairs/
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

输入:head = [1,2,3,4]
输出:[2,1,4,3]
题解:
方法一:迭代法
具体而言,交换之前的节点关系是temp -> node1 -> node2,交换之后的节点关系要变成 temp -> node2 -> node1,因此需要进行如下操作
在这里插入图片描述

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode(0);   //虚拟头节点
        dummy.next = head;
        ListNode prev = dummy;
        while(prev.next!=null && prev.next.next!=null){
            ListNode temp = head.next.next; // 缓存 next
            prev.next = head.next;          // 将 prev 的 next 改为 head 的 next
            head.next.next = head;          // 将 head.next(prev.next) 的next,指向 head
            head.next = temp;               // 将head 的 next 接上缓存的temp
            prev = head;                    // 步进1位
            head = head.next;               // 步进1位
        }

        return dummy.next;
    }
}
//时间复杂度: O(n)
//空间复杂度: O(1) 

5.删除链表的倒数第N个节点

https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。(1 <= n <= sz)
你能尝试使用一趟扫描实现吗?
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

思路:双指针
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。
这里我们待fast指向null的时候,slow指向的是要删除的前驱结点,直接slow.next=slow.next.next删除结点。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0,head);  //虚拟头节点
        ListNode fast = head;   //快指针
        ListNode slow = dummy;   //慢指针
        while(n-->0){
                fast=fast.next;     //快指针先移动n步
        }
        while(fast!=null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;     //删除结点
        return dummy.next;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LeetCode算法题合集—链表篇 的相关文章

随机推荐

  • 设计模式-访问者模式

    1 访问者模式被称为最复杂的设计模式 访问者模式访问者模式 Visitor pattern 是一种将数据结构与数据操作分离的设计模式 是指封装一些作用于某种数据结构中的各元素的操作 它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
  • png透明通道分离

    关于photoshop中png打开问题 前面也说到过http blog csdn net shenmifangke article details 52638716 ps在打开png格式图片的时候 实际上是把透明通道应用到了所有通道上 这样
  • IndentationError: unindent does not match any outer indentation level

    IndentationError unindent does not match any outer indentation level 遇到这个错误 是因为新的Python语法中是不支持的代码对齐中 混用TAB和空格的 解决方法 使用工具
  • 【C语言】之实现闰年判断

    文件名 leapYear c 功能 任意输入一个年份 判断其是否为闰年 编辑人 王廷云 include
  • VB+SQL银行设备管理系统设计与实现

    摘要 随着银行卡的普及 很多地方安装了大量的存款机 取款机和POS机等银行自助设备 银行设备管理系统可以有效的记录银行设备的安装和使用情况 规范对自助设备的管理 从而为用户提供更加稳定和优质的服务 本文介绍了银行设备管理系统的设计和开发过程
  • ooad设计模型

    设计模式 Design pattern 是一套被反复使用 多数人知晓的 经过分类编目的 代码设计经验的总结 使用设计模式是为了可重用代码 让代码更容易被他人理解 保证代码可靠性 毫无疑问 设计模式于己于他人于系统都是多赢的 设计模式使代码编
  • 前端之vue3使用动画库animate.css(含动画、过渡)

    动画与过渡 一 动画效果 1 默认动画 实例 动画语法 2 给transition指定name 二 过渡效果 三 多个元素过渡 四 vue3使用动画库 动画库animate css 五 总结 一 动画效果 1 默认动画 实例
  • github怎么自动更新被人更新过的项目_新出炉的免费开源平台,GitHub官方出品

    软件名称 GitHub Desktop 2 2 4 安装环境 Windows 下载链接 下载链接 https www sssam com 10822 html 软件简介 GitHub是一个面向开源及私有软件项目的托管平台 因为只支持git
  • 前端实现websocket(vue3)

    在config index js文件中配置一下websocket websocket的域名和端口号的配置 const BASE URL localhost const WS PORT 8080 const WS ADDRESS ws BAS
  • linux 查看连接数,并发数

    软连接 ln s home ictfmcg data photo var jtnd data photo tomcat 6的Connector配置如下
  • MAX30102 高灵敏度脉搏氧器和心率传感器说明书

    MAX30102 一 简介 MAX30102是一个集成的脉搏血氧测量和心率监测模块 它包括内部led 光电探测器 光学元件和具有环境光排斥作用的低噪声电子器件 MAX30102提供了一个完整的系统解决方案 以简化移动和可穿戴设备的设计过程
  • 【Hadoop 01】简介

    目录 1 Hadoop 简介 2 下载并配置Hadoop 2 1 修改 etc profile 2 2 修改hadoop env sh 2 3 修改core site xml 2 4 修改hdfs site xml 2 5 修改mapred
  • MySQL —— 基本查询

    文章目录 1 向表中插入数据 2 查询操作 2 1 全列查询 2 2 指定列查询 2 3 查询字段带表达式 2 4 为查询结果指定别名 2 5 去重操作 3 where 条件 3 1 比较运算符和逻辑预算符的运用 3 2 like的细节 3
  • 关于树莓派的VNC连接

    在使用树莓派时 会经常由于条件限制 无法配置全套外设 如显示器 键盘 鼠标 而需要用到手机或者电脑进行远程连接 树莓派除了支持putty进行SSH连接外 还可以通过tightvnc进行VNC连接 下面介绍一下两种远程连接方式的使用方法 1
  • uni-app接入uview-ui组件详细说明,希望对称有所帮助

    1 uni app 引入uViewUI uViewUI官方地址 https uviewui com 安装 如果您的根目录没有package json文件的话 请先执行如下命令 npm init y npm install uview ui
  • vue 实现简单表格分页功能

    使用框架实现表格展示和跳转功能 一直不懂原理 所以自己写一个简单的 加深理解 布局分为2块 上面是表格展示数据 下面是点击按钮跳转 效果图 代码
  • 利用神经网络识别12306验证码——(五)训练模型

    需要训练的有两个模型 一个是文本识别模型 一个是图像识别模型 在训练的时候 尝试了ResNet50 ResNet101 MobileNetV2 三种模型 前两个残差神经网络模型的参数比较大 训练比较耗时 精度上也逊色于第三个模型 尝试了RT
  • Android7.0以上自动更新安装apk

    Android7 0以上加了很多特性 也对系统做了很多的优化和升级 而在对Uri的访问上也做了改变 以下用安装apk的例子来说明 对于程序 我们要实现程序能够自动检查更新安装 我们需要给程序赋予权限
  • 狼人杀服务器维护时间,狼人杀官 方将于11月30日进行停机维护

    狼人杀官 方将于11月30日进行停机维护 此次更新将更改一些设定 新增活动和关闭前面的活动 优化和修复一下问题 狼友们可以了解一下更新内容 亲爱的狼队友 为了保证服务器的稳定和服务质量 我们将于2017年11月30日10 00进行停机维护工
  • LeetCode算法题合集—链表篇

    链表基础算法题 链表的定义 java 单链表的定义 public class ListNode int val ListNode next 指向下一节点 ListNode 无参构造 ListNode int val this val val