小白都能看懂的力扣算法详解——链表(二)

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

题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

24. 两两交换链表中的节点 - 力扣(LeetCode)

本题的难点在于如何将链表划分为两两一组。可以想到,用指针cur来标记每组元素的位置,交换完成后指针向后走两步,即为下一组元素的首个节点

 接下来思考第二个问题,如何实现每组元素之间的两两互换?通过小白都能看懂的力扣算法详解——链表(一)-CSDN博客这部分习题的练习,不难想到,让指针指向该节点的前一个节点,通过cur.next 和cur.next.next就能找到我们需要交换的两个节点了。

第三个问题,如何实现交换。这一步的方法有很多,只要注意不要乱了就可以。如图,链表的原先链接方式为黑色箭头,我们要把它变成红色箭头(千万不要忘记交换完1和2后,还要让1指向3)。我们这里采取使用两个临时指针temp1和temp2来记录1和3的地址,通过临时指针进行交换的方式。 

接下来考虑亿点点细节。首先是关于循环条件的判断。根据题目给出的示例不难发现,有链表节点是奇数和偶数个两种情况。当节点个数是奇数个时,退出循环的情况如下图所示,即cur.next.next;当节点个数是偶数个时,退出循环的情况为cur.next为空。所以循环判断条件可以写为cur.next != null && cur.next.next != null。这里需要注意&&前后的两个条件顺序不能交换!因为写在前面的条件会被优先判断,如果先判断cur.next.next的情况就有可能出现空指针异常。

接下来是对返回值的考虑。因为我们使用了虚拟头结点,所以不需要额外考虑头结点被换掉的情况,直接返回虚拟头节点的下一个节点就可以。至此,我们就可以愉快的写代码了。

 public ListNode swapPairs(ListNode head) {
        // 定义虚拟头节点和指针cur
        ListNode dh = new ListNode(0);
        dh.next = head;
        ListNode cur = new ListNode();
        cur = dh;
        // 定义两个临时指针
        ListNode temp1 = new ListNode();
        ListNode temp2 = new ListNode();
        // 进行交换
        while (cur.next != null && cur.next.next != null) {
            temp1 = cur.next;
            temp2 = cur.next.next.next;
            cur.next = cur.next.next;
            cur.next.next = temp;
            temp1.next = temp2;
            cur = cur.next.next;
        }
        return dh.next;
    }

 交换过程如下:

LC 19.删除链表中的第n个结点

题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

这道题可以类比数组的类似题型,考虑使用双指针(快慢指针)来寻找倒数第n个元素,我们让快指针fast比慢指针slow多走n步,之后两个指针同时向前,当快指针遍历结束时,慢指针刚好走到倒数第n个元素的位置上。

思路考虑完毕,接下来考虑细节处理。首先是如何进行"删除"操作,根据以往经验,我们需要让慢指针走到待删除节点的前一个节点,因此我们只要在原有思路基础上,让fast快指针再多走一步,这样快指针遍历结束时,慢指针就走到了倒数第n+1个元素的位置上,也就是待删除节点的前一个节点。让slow.next = slow.next.next即可。

那么我们又要如何实现让快指针多走n+1步呢?我们这里采用了for循环的方式,让fast = fast.next操作进行n+1次,这里需要额外注意一下边界的判断,因为i是从0开始的,所以循环到i>n时结束,刚好是n+1次。

最后是对特殊情况(如链表只有头节点)的考虑,由于我们使用了虚拟头节点,因此如果头节点被删掉,那么返回虚拟头节点的下一个节点,也就是null满足。那么会不会出现n大于链表中节点个数或者链表为空的情况呢?至少在本题中无需考虑。

public ListNode removeNthFromEnd(ListNode head, int n) {
        // dummyNode 虚拟头节点
        ListNode dn = new ListNode();
        dn.next =head;
        // 快慢指针
        ListNode fast = dn;
        ListNode slow = dn;
        for(int i = 0; i <= n; i++) {
            fast = fast.next;
        }
        // 快慢指针同时走,直到块指针遍历结束
        while(fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        // 找到待删除节点前一个节点,删除
        slow.next = slow.next.next;
        return dn.next;
    }
  

 

LC 面试02.07 链表相交

题目描述:

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

面试题 02.07. 链表相交 - 力扣(LeetCode)

 这道题卡尔哥的解法也很妙,不难观察出,两条链表在相交后,后半段的长度是一样的,那么只要我们求出两条链表长度的差值,然后让两条链表的尾巴对对齐,比较各节点的值即可。具体解法可以参考代码随想录代码随想录 (programmercarl.com),有很多图示更加直观。

这里我想介绍另一种思路。观察以上两个示例或者我画的这个很抽象的图,可以发现,链表A的长度加上B的前半部分刚好等于链表B的长度加上A的前半部分,那么我们可以让两个指针p和q分别遍历链表A、B,当遍历结束后,就返回到链表B、A的头节点继续遍历另一条链表,当两个指针相遇时(说明它俩走了相同的步数),即为我们寻找的节点位置。

这个思路来源于b站【LeetCode 每日一题】160. 相交链表 | 手写图解版思路 + 代码讲解_哔哩哔哩_bilibili

 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // 解法1
        ListNode p = headA;
        ListNode q = headB;
        while(p != q) {
            p = (p != null ? p.next :headB);
            q  = (q != null ? q.next : headA);
        }
        return q;
        // 解法2
        //  ListNode curA = headA;
        // ListNode curB = headB;
        // int lenA = 0, lenB = 0;
        // while (curA != null) { // 求链表A的长度
        //     lenA++;
        //     curA = curA.next;
        // }
        // while (curB != null) { // 求链表B的长度
        //     lenB++;
        //     curB = curB.next;
        // }
        // curA = headA;
        // curB = headB;
        // // 让curA为最长链表的头,lenA为其长度
        // if (lenB > lenA) {
        //     //1. swap (lenA, lenB);
        //     int tmpLen = lenA;
        //     lenA = lenB;
        //     lenB = tmpLen;
        //     //2. swap (curA, curB);
        //     ListNode tmpNode = curA;
        //     curA = curB;
        //     curB = tmpNode;
        // }
        // // 求长度差
        // int gap = lenA - lenB;
        // // 让curA和curB在同一起点上(末尾位置对齐)
        // while (gap-- > 0) {
        //     curA = curA.next;
        // }
        // // 遍历curA 和 curB,遇到相同则直接返回
        // while (curA != null) {
        //     if (curA == curB) {
        //         return curA;
        //     }
        //     curA = curA.next;
        //     curB = curB.next;
        // }
        // return null;
    }

LC 142.环形链表II

题目描述:

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

142. 环形链表 II - 力扣(LeetCode)

本题是对141判断链表是否成环的进阶考法,更像是对数学能力的考察(关于数学证明可以参考力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台)。具体代码大家可以直接去看视频讲解,会更加直观(这里需要注意的是因为快指针一次走两步,所以需要满足fast != null && fast.next != null)把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II_哔哩哔哩_bilibili

public ListNode detectCycle(ListNode head) {
        // 判断是否成环:快慢指针相遇
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {// 有环
                ListNode index1 = fast; // 相遇节点
                ListNode index2 = head; 
                // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ARP欺骗攻击利用之内网截取图片

Arp欺骗&#xff1a;目标ip的流量经过我的网卡&#xff0c;从网关出去。 Arp断网&#xff1a;目标ip的流量经过我的网卡 1. echo 1 >/proc/sys/net/ipv4/ip_forward 设置ip流量转发&#xff0c;不会出现断网现象 有时不能这样直接修改&#xff0c;还有另外一种方法 修…

时刻陪伴,爱意无限

情人节即将到来&#xff0c;你是否在寻找一份特别的礼物&#xff0c;既能表达你的心意&#xff0c;又能带来实用的陪伴&#xff1f;那么&#xff0c;华为WATCH GT 4或许是你的不二之选。 华为 WATCH GT 4有两种不同的外观&#xff0c;颜值都超能打。一款是简洁大气的圆形表盘&…

2024年10 个好用的AI简历工具盘点推荐

在职场竞争激烈的今天&#xff0c;一份出色的简历就像是你的秘密武器&#xff0c;能帮你在众多候选人中脱颖而出&#xff0c;赢得面试宝座。随着 ChatGPT 引领的 AI 浪潮席卷而来&#xff0c;各式各样的 AI 简历工具如雨后春笋般涌现。面对这样的背景&#xff0c;神器集今天为大…

C++,stl,栈stack和队列queue详解

1.栈stack 1.stack基本概念 2.stack常用接口 代码示例&#xff1a; #include<bits/stdc.h> using namespace std;int main() {stack<int> stk;stk.push(7);stk.push(9);stk.push(5);cout << "栈的size为&#xff1a;" << stk.size() <…

如何写一个其他人可以使用的GitHub Action

前言 在GitHub中&#xff0c;你肯定会使用GitHub Actions自动部署一个项目到GitHub Page上&#xff0c;在这个过程中总要使用workflows工作流&#xff0c;并在其中使用action&#xff0c;在这个使用的过程中&#xff0c;总会好奇怎么去写一个action呢&#xff0c;所以&#xff…

尚硅谷 Vue3+TypeScript 学习笔记(上)

目录 一、创建Vue3工程 1.1. 【基于 vue-cli 创建】 1.2. 【基于 vite 创建】(推荐) 1.3. 【一个简单的效果】 二、Vue3核心语法 2.1. 【OptionsAPI 与 CompositionAPI】 Options API 的弊端 Composition API 的优势 2.2. 【拉开序幕的 setup】 setup 概述 setup 的…

11 串口发送应用之使用状态机实现多字节数据发送

1. 使用串口发送5个字节数据到电脑 uart协议规定&#xff0c;发送的数据位只能是6&#xff0c;7&#xff0c;8位&#xff0c;如果数据位不符合&#xff0c;接收者接收不到数据。所以我们需要将40位数据data分为5个字节数据分别发送&#xff0c;那么接收者就能通过uart协议接收…

django微博热搜数据分析与可视化系统python毕业设计

简而言之&#xff0c;数据可视化是以图形方式呈现结构化或非结构化数据&#xff0c;从而将隐藏在数据中的信息直接呈现给人们。但是有一个陷阱:它不仅仅是使用数据可视化工具将数据转化为图形。相反&#xff0c;它是从数据的角度看待世界。换句话说&#xff0c;数据可视化的对象…

在django中集成markdown文本框

首先需要下载开源组件&#xff1a;http://editor.md.ipandao.com/&#xff0c;可能需要挂梯子。 百度网盘&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1D9o3P8EQDqSqfhAw10kYkw 提取码&#xff1a;eric 1.在html代码中生成一个div&#xff0c;ideditor <div c…

[Python] 深入理解列表和元组

在学习的C语言中有数组可以用来存储数据&#xff0c;那么在Python中是否也有这样的工具呢&#xff1f;接下来让可莉来给大家讲解列表和元组这两个强力工具吧~ 专栏&#xff1a;《Python》 blog&#xff1a;Keven ’ s blog 在 Python 中&#xff0c;列表和元组是两种常用的序列…

【MySQL进阶之路】BufferPool底层设计(下)

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

购物|电商购物小程序|基于微信小程序的购物系统设计与实现(源码+数据库+文档)

电商购物小程序目录 目录 基于微信小程序的购物系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户前台功能实现 2、管理员后台功能实现 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&#xff1a; 五、核心代码 六、论文参考 七、最新计算机毕设…

MySQL数据库——索引

索引是数据结构&#xff0c;用于高效获取数据的数据结构&#xff08;有序&#xff09;。 1、索引的优缺点&#xff1a; 1.1、优点&#xff1a; a、提高数据检索效率&#xff0c;降低数据库的IO成本&#xff08;提高查询效率&#xff09; b、通过索引列对数据进行排序&#…

ClickHouse--01--简介

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1. ClickHouse 简介1.1 大数据处理场景1.2 什么是 ClickHouse1.3 OLAP 场景的特征 2. ClickHouse 特性2.1 完备的 DBMS 功能2.2 列式存储行式存储: 在数据写入和修改…

玉米基因miRNA结合位点预测工具

前记 目前&#xff0c;已经有很多种玉米miRNA结合位点预测工具可供选择&#xff0c;以下几种比较常用&#xff1a; 1、psRNATarget&#xff1a;该工具是由华盛顿州立大学开发的&#xff0c;可以用来预测植物miRNA和靶基因之间的相互作用。用户可以使用该工具来预测玉米miRNA和结…

【Web】vulhub Shiro-550反序列化漏洞复现学习笔记

目录 Shiro简介 复现流程 工具一把梭 半脚本半手动 原理分析 反序列化入口 常见的key 登录过程 验证过程 利用原理 Shiro简介 Apache Shiro 是一个强大且易于使用的 Java 安全框架&#xff0c;用于身份验证、授权、加密和会话管理等安全功能。Shiro 的设计目标是简单…

C++入门全集(1):初窥门径

一、前言 C是一种计算机高级程序设计语言&#xff0c;它在C语言的基础上进行了进一步的扩充和完善&#xff0c;并增加了许多有用的库&#xff0c;是一种面向对象的程序设计语言。 所以&#xff0c;C是兼容C语言语法的。 我打算把所有C入门需要学习的知识整合成一个全集&…

DNS 域名系统——应用层

目录 1 域名系统 DNS 1.1 域名系统 1.2 互联网的域名结构 1.2.1 顶级域名 TLD(Top Level Domain) (1) 国家顶级域名 nTLD (2) 通用顶级域名 gTLD (3) 基础结构域名 (infrastructure domain) 1.3 域名服务器 1.3.1 域名服务器的四种类型 &#xff08;1…

bpmn.js一个基于Bpmn 2.0的前端工作流展示和绘制工具

bpmn.js是由开源工作流引擎camunda内部组织BPMN.IO组织开发的一款基于BPMN 2.0的工作流展示、编辑的web端工具库。由于工作流引擎activiti、flowable、camunda属于同宗分流&#xff0c;其工作流定义格式大致相同&#xff0c;所以我们可以使用bpmn.js完美融合其中任一工作流引擎…

使用 openpyxl 操作 Excel

由于单位有任务&#xff0c;需要按照名册制作多个工作表。手动复制和修改内容太费事了&#xff0c;所以使用python完成此项工作&#xff0c;为之后的此类工作提供一个通用脚本。 安装依赖库 pip install openpyxl lxml我们需要用到openpyxl。在官方文档中提到&#xff0c;如果…