LeetCode链表相关解法

news2024/10/6 1:46:08

LeetCode链表相关解法

    • 1.移除链表元素
      • [203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/)
        • 不设置头节点
        • 设置虚拟头节点
    • 2.设计链表
      • [707. 设计链表](https://leetcode.cn/problems/design-linked-list/)
    • 3.反转链表
      • [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/)
        • 思路
        • 代码
    • 4.两两交换链表节点
      • [24. 两两交换链表中的节点](https://leetcode.cn/problems/swap-nodes-in-pairs/)
    • 5.删除链表的倒数第N个节点
      • [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/)
        • 思路
        • 代码
    • 6.链表相交
      • [面试题 02.07. 链表相交](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/)
      • 双指针法
        • 思路
      • 哈希法
    • 7.环形链表II
      • [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/)
      • 哈希法
      • 双指针法

LeetCode一般提供的链表节点结构如下

public class ListNode {
    // 结点的值
    int val;

    // 下一个结点
    ListNode next;

    // 节点的构造函数(无参)
    public ListNode() {
    }

    // 节点的构造函数(有一个参数)
    public ListNode(int val) {
        this.val = val;
    }

    // 节点的构造函数(有两个参数)
    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
}

1.移除链表元素

203. 移除链表元素

不设置头节点

需要先进行删除,保证第一位不是目标元素

然后再进行后面的遍历

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //处理第一位,注意是while
        while(head != null && head.val == val){
            head = head.next;
        }

        if(head == null){
            return head;
        }

        ListNode pre = head;
        ListNode current = head.next;

        while(current != null){
            if(current.val == val){
                current = current.next;
                pre.next = current;
            }else{
                current = current.next;
                pre = pre.next;
            }
        }

        return head;
    }
}

设置虚拟头节点

设置一个虚拟头节点,方便操作

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head == null){
            return head;
        }
         //添加一个虚拟头节点
        ListNode VirtualHead = new ListNode(-1, head);
        ListNode pred = VirtualHead;
        ListNode cur = head;
        while(cur != null){
            if(cur.val == val){
                cur = cur.next;
                pred.next = cur;
            }else{
                cur = cur.next;
                pred = pred.next;
            }
        }
        return VirtualHead.next;
    }
}

2.设计链表

707. 设计链表

先找前驱节点

class LinkedNode {
    int val;
    LinkedNode next;
    public LinkedNode(){}
    public LinkedNode(int val){
        this.val = val;
    }
}
class MyLinkedList {
    //size存储链表元素的个数
    int size;
    //虚拟头结点
    ListNode head;

    //初始化链表
    public MyLinkedList() {
        size = 0;
        head = new ListNode(-1);
    }
    
    public int get(int index) {
        //如果index非法,返回-1
        if (index < 0 || index > size-1) {
            return -1;
        }
        int curIndex = 0;
        ListNode cur = head.next;
        while(cur != null){
            if(curIndex == index){
                return cur.val;
            }
            cur = cur.next;
            curIndex++;
        }
        return -1;
    }
    
    public void addAtHead(int val) {
        addAtIndex(0, val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(size, val);
    }
    
    // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
    // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
    // 如果 index 大于链表的长度,则返回空
    public void addAtIndex(int index, int val) {
        if(index >= size-1){
            return;
        }
        if (index < 0) {
            index = 0;
        }
        //找到要插入节点的前驱
        ListNode pre = head;
        for (int i = 0; i < index; i++) {
            pre = pre.next;
        }
        ListNode newNode = new ListNode(val);
        newNode.next = pre.next;
        pre.next = newNode;
        size++;
    }
    
    public void deleteAtIndex(int index) {
        if (index < 0 || index > size-1) {
            return;
        }
        if (index == 0) {
            head = head.next;
	        return;
        }
        ListNode pre = head;
        for (int i = 0; i < index ; i++) {
            pre = pre.next;
        }
        pre.next = pre.next.next;
        size--;
    }
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

3.反转链表

206. 反转链表

思路

利用双指针,将所有的节点的next进行反转

img

注意点

  • 开始的时候pre为null
  • 结束条件为cur == null
  • 当前节点的next已经被修改了,cur如何到下一个节点? 使用temp临时指针

代码

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pred = null;
        ListNode cur = head;

        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pred;
            pred = cur;
            cur = temp;
        }

        return pred;
    }
}

4.两两交换链表节点

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

模拟题,A->B->C->D顺序如下

  1. 后一个节点B的指针指向前一个节点A
  2. A指向B的下一个节点C
  3. 之前的节点连接到B

注意点如下:

  • 开始时进行判断.如果节点个数小于2直接返回
  • 初始化时,pred和cur都为head,在进入循环后cur再为pred.next,避免空指针
  • 结束条件为剩下的节点不足两个
  • B节点指向A后,不知道C在哪了,所以需要一个临时指针temp指向C
  • B节点到了链表头部后,需要一个连接指针link来把头节点来指向B
/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }

        ListNode virtualHead = new ListNode(-1, head);
        ListNode pred = head;
        ListNode cur = head;
        ListNode link = virtualHead; //记录之前连接到哪个节点了
        while(pred != null && pred.next != null){
            //在这里才真正赋值,因为pred!=null可用保证不会空指针
            cur = pred.next;
            
            //更改连线
            ListNode temp = cur.next;
            cur.next = pred;
            pred.next = temp;
            link.next = cur;

            //移动
            link = pred;
            pred = pred.next;
            
        }
        return virtualHead.next;

    }
}

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

19. 删除链表的倒数第 N 个结点

思路

删除一个节点需要知道这个节点的上一个节点

我们可用定义两个快慢指针

  1. 快指针先走N步

image-20230130035254274

  1. 然后快慢指针一起走,直到快指针的下一个为null

image-20230130035346055

  1. 这时候慢指针删除下一个节点

代码

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode virtualHead = new ListNode(-1, head);
        ListNode fast = virtualHead;
        ListNode slow = virtualHead;
        for(int i = 0; i < n; i++){
            fast = fast.next;
        }
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }

        //删除节点
        slow.next = slow.next.next;
 
        return virtualHead.next;
    }
}

6.链表相交

面试题 02.07. 链表相交

双指针法

思路

  1. 先各自获得链表的长度A B

  2. 假如A长,A链表从A-B的地方开始和B一起遍历

  3. 依次比较指针是否相等

计算一下两个链表的长度,让长链表先走,等两个链表长度一样的时候再一起走,结点相等直接返回,没有相交返回null

面试题02.07.链表相交_2
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = 0, lenB = 0;
        ListNode curA = headA;
        ListNode curB = headB;

        //获取长度
        while(curA != null){
            lenA++;
            curA = curA.next;
        }
        while(curB != null){
            lenB++;
            curB = curB.next;
        }

        //让长的为headA,短的为headB
        if(lenA < lenB){
            int temp = lenA;
            lenA = lenB;
            lenB = temp;
            ListNode tempNode = headA;
            headA = headB;
            headB = tempNode;
        }

        curA = headA;
        curB = headB;
        int gap = lenA - lenB;
        //长的走到和短的相同的地方
        for(int i = 0; i < gap; i++){
            curA = curA.next;
        }

        while(curA != null){
            if(curA == curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }

        return null;
    }
}

哈希法

先把其中一个链表的节点都放入HashSet,然后放入另一个链表的节点,如果有包含的话,就说明是同个节点

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        HashSet set = new HashSet();
        ListNode curA = headA;
        ListNode curB = headB;

        while(curA != null){
            set.add(curA);
            curA = curA.next;
        }

        while(curB != null){
            if(set.contains(curB)){
                return curB;
            }
            curB = curB.next;
        }

        return null;
    }
}

7.环形链表II

142. 环形链表 II

哈希法

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        HashSet set = new HashSet();
        ListNode cur = head;


        while(cur != null){
            if(set.contains(cur)){
                return cur;
            }
            set.add(cur);
            cur = cur.next;
        }

        return null;
    }
}

双指针法

https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#_142-%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8ii

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

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

相关文章

使用Java8改造模板方法模式

目录 前言 以前的模板方法 Java 8 的函数式编程 Java 8以后的模板方法 总结 前言 我们在日常开发中&#xff0c;经常会遇到类似的场景&#xff1a;当要做一件事儿的时候&#xff0c;这件事儿的步骤是固定好的&#xff0c;但是每一个步骤的具体实现方式是不一定的。 通…

Hudi(14):Hudi集成Flink之核心参数设置

目录 0. 相关文章链接 1. 去重参数 2. 并发参数 2.1. 参数说明 2.2. 案例演示 3. 压缩参数 3.1. 参数说明 3.2. 案例演示 4. 文件大小 4.1. 参数说明 4.2. 案例演示 5. Hadoop 参数 Flink可配参数官网地址&#xff1a;All Configurations | Apache Hudi 0. 相关文…

Ubuntu 18.04 安装 nvidia 显卡驱动 离线安装 禁用 nouveau

Ubuntu 18.04 安装 nvidia 显卡驱动 离线安装1 系统2 查看显卡2.1 更新 pci.ids 文件3 安装显卡驱动 510.543.1 安装 nvtop4 禁用 nouveau5 安装 cuda 11.6.15.1 设置环境变量1 系统 # lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubu…

bpflock:基于eBPF实现的Linux设备安全审计工具

关于bpflock bpflock是一款基于 eBPF驱动的Linux设备安全审计工具&#xff0c;该工具使用了eBPF来帮助广大研究人员增强Linux设备的安全性。通过限制对各种Linux功能的访问&#xff0c;bpflock能够减少攻击面并阻止一些众所周知的攻击技术。 bpflock只允许类似容器管理器、sy…

区间一维dp史上最细总结(听了绝对会了,还不会的一定要进来)

目录 那年初夏&#xff08;三&#xff09; 引入 1.动态规划是什么&#xff1f; 2.什么是区间动态规划问题&#xff1f; 定义 性质 3.为何总是要问这种问题&#xff1f; 区间动态规划基本 思考 步骤&#xff08;划重点&#xff09; 例题精讲 1.最长上升子序列 题目描…

8个 数据库性能优化方案,你知道几个?(建议收藏)

毫不夸张的说咱们后端工程师&#xff0c;无论在哪家公司&#xff0c;呆在哪个团队&#xff0c;做哪个系统&#xff0c;遇到的第一个让人头疼的问题绝对是数据库性能问题。如果我们有一套成熟的方法论&#xff0c;能让大家快速、准确的去选择出合适的优化方案&#xff0c;我相信…

IB数学AA/AI应该如何选择?

IB数学怎么选课&#xff1f;AA&#xff0c;AI&#xff0c;SL&#xff0c;HL适合哪些学生&#xff1f;如何学习&#xff1f;IB数学&#xff1a;AA与AI&#xff0c;到底应该怎么选&#xff1f;IB数学AA有多难&#xff1f;要不要学数学AA HL&#xff1f;适合学生 IB数学AA AA HL偏…

【SpringCloud复习巩固】Feign

目录 一.HTTP客户端Feign 1.1RestTemplate方式调用存在的问题 1.2Feign的介绍 1.3Feign的使用 1.4自定义Feign的配置 1.4.1配置Feign日志的两种方式 1.5Feign性能优化 1.5.1Feign的性能优化-连接池配置 1.6Feign的最佳实践 一.HTTP客户端Feign 1.1RestTemplate方式调用…

自学软件测试,现在年薪30w,我骄傲了吗?

从小老一辈的人就经常说&#xff0c;小时候不好好读书&#xff0c;长大了只能去工地搬砖。我是从小都不爱读书的人&#xff0c;但在上学时期我一直有一种优越感&#xff0c;认为自己读书很有天赋&#xff0c;读书就是比别人厉害&#xff0c;但事实证明也确实如此&#xff0c;高…

[Android Studio]Android Studio Logcat日志样式设置

&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea; Android Debug&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea; Topic 发布安卓学习过程中遇到问题解决过程&#xff0c;希望我的解决方案可以对小伙伴们有帮助。 &#x1f4cb;笔记目…

c++IO流!!!开工了!!!

1.什么是IO流 流是若干个字节组成的字节序列&#xff0c;简单来说指的是就是数据从一端到另一端 键盘到程序——>标准输入流程序到屏幕——>标准输出流程序到文件——>文件流 流类体系&#xff1a;一些体系管理输入和输出的流的操作 输入流输出流文件流 ios类 istream…

【DockerCE】使用docker配置和运行HertzBeat

HertzBeat是一款免Agent的监控平台&#xff0c;拥有强大自定义监控能力&#xff0c;可以对应用服务、中间件、数据库、操作系统、云原生等进行监控&#xff0c;配置监控告警阈值&#xff0c;以及告警通知(邮件、微信、钉钉、飞书)。关于这个软件的介绍&#xff0c;我这里就不做…

困扰多年的Docker和iptables的恩怨,今天解决了

先介绍下我的使用环境&#xff1a; 操作系统&#xff1a;CentOS7.9 Docker版本&#xff1a;20.10.21 事情是这样的&#xff0c;安装完Docker的时候&#xff0c;容器镜像都跑起来了&#xff0c;端口也放行了&#xff0c;就是无法控制系统防火墙friewalld,查看firewalld状态报错 …

【微信小游戏开发笔记】第一节:微信小游戏Cocos开发环境配置

微信小游戏开发环境配置 微信小游戏开发前&#xff0c;首先要做一些准备&#xff1a; 注册 微信公众平台 账号&#xff0c;获取小游戏AppID(小程序ID)。安装 微信开发者工具&#xff0c;用于编译小游戏。安装 Visual Studio Code&#xff0c;用于编写游戏逻辑代码。安装并配置…

Linux命令:wget(下载文件)、ssh(登录及免密登录)、scp(远程文件传输)、sh(脚本)

wget 概述 wget是一个下载文件的工具&#xff0c;用在命令行下&#xff0c;下载一些软件或从远程服务器恢复备份到本地服务器 wget支持HTTP&#xff0c;HTTPS和FTP协议&#xff0c;可以使用HTTP代理 支持自动下载 wget可以在用户退出系统的之后在后台执行。意味着你可以登…

C语言选择排序和快速排序(图解过程)+思路清晰

选择排序和快排选择排序时间复杂度和空间复杂度快排&#xff08;三种方式&#xff09;1.hoar时间复杂度和空间复杂度优化--三数取中优化--小区间优化2.挖坑法3.双指针&#xff08;推荐&#xff09;选择排序 本篇文章的重点在快排。因为选择排序无论是在思想上面还是&#xff0…

提供数百万岗位和丰厚利润,苹果却转移产业链,中国制造怎么办?

新年刚过&#xff0c;就传出消息指苹果直接代中国供应链企业向印度提出建厂申请&#xff0c;其中有14家获得了许可&#xff0c;而3家被否决&#xff0c;这凸显出苹果坚定向印度转移生产线&#xff0c;如此做对中国制造将产生深远影响。一、苹果对中国制造的影响巨大苹果为中国提…

新的一年,这份高级测试人的职业素养请收好~

软件测试工程师需要的专业技能计算机领域的专业技能是测试工程师应该必备的一项素质&#xff0c;是做好测试工作的前提条件。尽管没有任何IT背景的人也可以从事测试工作&#xff0c;但是一名要想获得更大发展空间或者持久竞争力的测试工程师&#xff0c;则计算机专业技能是必不…

5G R16+C-V2X赋能下一代智能T-Box,助力智能驾驶时代加速到来

█ 5G技术助力C-V2X持续进化&#xff0c;智能网联新生态逐步建立 汽车行业正面临百年未有之变局&#xff0c;智能汽车已经成为全球汽车产业发展的战略方向。发改委、工信部、交通部等11部委联合印发的《智能汽车创新发展战略》中指出&#xff1a;汽车产业与相关产业全面融合&a…

(二十四)深入理解蓝牙BLE之“H5协议”

前言&#xff1a;蓝牙产品在实际落地中&#xff0c;很多时候采用hostcontroller的通信模型&#xff0c;其中host负责实现协议栈profile是运行在主控cpu上的。controller为另外一颗单独的蓝牙芯片&#xff0c;负责蓝牙link layer的处理&#xff0c;两个芯片通过hci消息来交互数据…