【数据结构】:大厂面试经典链表OJ题目详解

news2024/12/26 0:02:40

image.png

反转链表

206. 反转链表 - 力扣(LeetCode)
image.png|488

思路解透

image.png|447
本题就是通过不停地将最先的 head 节点位置的后一位插到最前面,完成链表的反转
本题需要两个节点变量

  1. cur:其任务就是定位到 head 节点位置的前一位,然后将自己插入到当前 head 节点的前面
    • 因为链表的最后一个节点都是指向一个 null 值,所以需要将最先的 head 节点的 next 置为空
    • 但在将 head.next 置为 null 之前,需要先将 cur 节点实例化出来,不然 cur 就无法找到原先的 head 节点的位置了
  2. curN:其任务就是定位到 cur 的后一个节点,方便让 cur 进行循环插入
    • 其在循环中进行实例化,因为每一次插入完成之后,curN 的位置都是需要随着 cur 的改变而改变
    • curN 实例化为 cur 的下一个节点。在 cur 插入完成后,cur 就会定位到 curN 的位置,若此为止不为 null,则继续进行前插

代码解析

class Solution {
    public ListNode reverseList(ListNode head) {
        //1. 防止空指针异常  
		if(head == null){  
    		return head;  	
		}  
		  
		//2. 将head.next置为空  
		//注意先把 cur 节点给先弄出来  
		ListNode cur = head.next;  
		head.next = null;  
		  
		//3. 进行循环头插  
		while (cur != null) {  
		    ListNode curN = cur.next;  
		    cur.next = head;  
		    head = cur;  
		    cur = curN;  
		}  
		return head;
	}
}

寻找中间节点

876. 链表的中间结点 - 力扣(LeetCode)
image.png|613

思路解透

解法 1:定义一个 cur 节点,从 head 节点的地方,向后走 size()/2 步,就到了中间位置
解法 2:定义一个 slow 节点,一次走一步,在定义一个 fast 节点,一次走两步,当 fast 走完的时候,slow 就刚好在中间位置(快慢指针

  • 当有偶数个节点时,循环判断条件为:fast != null
  • 当有奇数个节点时,循环判断条件为:fast.next != null
  • 这里的两个条件判断顺序不能换,否则会报空指针异常错误

快慢指针原理:
路程一样的情况下,速度是两倍,那么当走完的时候,路程也是两倍

代码解析(法 1)

public ListNode middleNode(){  
    int count = 0;  
    ListNode node = head;  
    while(node != null){  
        count++;  
        node = node.next;  
    }    
    ListNode cur = head;  
    for (int i = 0; i < count/2; i++) {  
        cur = cur.next;  
    }    
    return cur;  
}

代码解析(法 2)

public ListNode middleNode(){  
    ListNode slow = head;  
    ListNode fast = head;  
    while(fast != null && fast.next != null){  
    	//slow走一步,fast走两步
        slow = slow.next;  
        fast = fast.next.next;  
    }    
    return slow;  
}

返回链表中倒数第 k 个节点

面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)
image.png|533

思路解透

  1. 首先判断 k 是否合法,链表是否为为 null
    1. k <= 0,返回-1
    2. (下面的第二点看完再回来)因为如果 k 大于链表长度的话,当 fastk - 1 步的时候就会走出链表,所以在 fastk-1 步的过程中如果出现 fast == null,则返回 -1
  2. 定义两个节点,fast 先走 k - 1 步,随后 fastslow 一起走,当 fast 走到最后了,slow 所在的地方就是倒数第 k 个节点

代码解析

public int kthToLast(int k) {  
	//判断k是否合法,链表是否为null
    if(k <= 0 || head == null) {  
        return -1;  
    }    
    ListNode fast = head;  
    ListNode slow = head;  
    int count = 0;  
    while (count != k - 1) {  
        //fast先向后走k-1步        
        fast = fast.next;  
        if(fast == null){
        //判断k是否合法
            return -1;  
        }
        count++;  
    }    
    while (fast.next != null){
    	//两个节点一起向后走,直到fast走到最后一个  
        fast = fast.next;  
        slow = slow.next;  
    }    
    return slow.val;  
}

合并两个有序链表

21. 合并两个有序链表 - 力扣(LeetCode)
image.png|546

思路解透

创建一个新的链表,为虚拟节点(傀儡节点),然后对需要合并的两个链表中的值进行比较,谁小谁就接在虚拟节点后面

  1. 创建一个新的节点 newH,在这个链表上进行合并,再创建一个 tmp 节点,用来指向 newH 链表中的最后一个节点
  2. headA != null && headB != null 的时候,进行比较
    1. headA. val < headB. val,则将 headA 这个节点接在 newH 后面,即接在 tmp 节点后面,最后 tmpheadB 节点均向后移一位
    2. headA. val > headB. val,则将 headB 这个节点接在 newH 后面,即接在 tmp 节点后面,最后 tmpheadB 节点均向后移一位
  3. headA == null || headB == null 的时候,剩下的一个链表里面的节点直接接到 newH 后面就行了
  4. 最后返回 newH. next,因为 newH 是一个虚拟节点,不存在于要合并的链表中,它只是一个引子

代码解析

public ListNode mergeTwoLists(ListNode headA, ListNode headB) {  
    ListNode newH = new ListNode(0);  
    ListNode tmp = newH;  
    while(headA != null && headB != null){  
        if(headA.val < headB.val){  
        	//将headA接到newH上面,随后后移
            tmp.next = headA;  
            headA = headA.next;  
            tmp = tmp.next;  
        }else if{  
        	//将headB接到newH上面,随后后移
            tmp.next = headB;  
            headB = headB.next;  
            tmp = tmp.next;  
        }    
    }    
    if(headA == null){  
    	//headA空了,将headB直接接到newH后面
        tmp.next = headB;  
    }    
    //headB空了,将headA直接接到newH后面
    if (headB == null) {  
        tmp.next = headA;  
    }    
    return newH.next;  
}

分割链表

链表分割_牛客题霸_牛客网 (nowcoder.com)
image.png

思路解透

构建两个区间,一个里面接上小于 x 的节点,一个里面接上大于 x 的节点,最后将这两个区间连接起来

  1. 若链表为空
  2. 遍历链表
    • 创建一个 cur 节点,用来遍历链表
  3. 把对应的节点放到指定区间
    1. 在小区间里
      1. 创建 bs(before start) 节点指向区间里面最前面的一个节点,创建 be(before end) 节点指向区间里面最后一个节点
      2. 在小区间里面插入第一个节点的时候,bsbe 都指向这个节点,随后 cur 向后移
      3. 之后插入的节点均为尾插,bs 位置不变,be 始终指向新插入的节点
    2. 在大区间里
      1. 创建 as(after start) 节点指向区间里面最前面的一个节点,创建 ae(after end) 节点指向区间里面最后一个节点
      2. 在小区间里面插入第一个节点的时候,asae 都指向这个节点,随后 cur 向后移
      3. 之后插入的节点均为尾插,as 位置不变,ae 始终指向新插入的节点
  4. 把两个区间连接起来
    1. be 节点和 as 节点连接起来,并且将 ae 节点的 next 置为 null,作为新链表的尾巴,并且返回 bs 节点
    2. 若所有节点全在小区间里,就将 be 节点的 next 置为 null,作为新链表的尾巴,并且返回 bs 节点
    3. 若全在大区间里,则返回 ae 节点

代码解析

public ListNode partition(ListNode pHead, int x) {  
    //判断空链表
    if(pHead == null){  
        return null;  
    }      
    //小区间的两个节点
    ListNode bs = null;  
    ListNode be = null;  
    //大区间的两个节点
    ListNode as = null;  
    ListNode ae = null;  
	
	//遍历链表的节点
    ListNode cur = pHead;  
    while(cur != null){  
    	//插入小区间
        if(cur.val < x){  
        	//第一次插入
            if(bs == null){  
                bs = be = cur;  
            }else{  
                be.next = cur;  
                be = be.next;  
            } 
        //插入大区间       
        }else{  
        	//第一次插入
            if(as == null){  
                as = ae = cur;  
            }else{  
                ae.next = cur;  
                ae = ae.next;  
            }        
        }        
    cur = cur.next;  
    }    
    //当节点全部都在小区间时,直接返回大区间
    if(bs == null){  
        return as;  
    }    
    
    //进行大小区间的拼接
    be.next = as;  
    //大区间不为空,把最后一个节点置空,作为尾巴
    if(as != null){  
        ae.next = null;  
    }  
    return bs;  
}

回文链表

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)
image.png|579

思路解透

  1. 首先用快慢指针找到中间的节点(上面第二题有讲解)
  2. 再对后半部分进行反转(上面第一题有讲解)
  3. 最后让首尾两个节点往中间走,直到相遇,返回 true;若是偶数个节点,则只需要前面节点的 next 与后面节点的值相等即可返回 true

代码解析

public boolean chkPalindrome(ListNode head) {  
    // write code here  
    if (head == null) {  
        return true;  
    }  
    //1. 找到链表的中间节点  
    ListNode fast = head;  
    ListNode slow = head;  
  
    while (fast != null && fast.next != null) {  
        slow = slow.next;  
        fast = fast.next.next;  
    }  
    //2. 反转后半节点  
    ListNode cur = slow.next;  
    slow.next = null;  
    while (cur != null) {  
        ListNode curN = cur.next;  
        cur.next = slow;  
        slow = cur;  
        cur = curN;  
    }  
    //3. slow从后往前,head从前往后,直到相遇  
    while (head != slow) {  
        if (head.val != slow.val) {  
            return false;  
        }        
        //当节点个数为偶数
        if (head.next == slow)  
            return true;  
        head = head.next;  
        slow = slow.next;  
    }    
    return true;  
}

相交链表

160. 相交链表 - 力扣(LeetCode)
image.png|572

思路解透

  1. 首先计算两个链表的长度,并计算他们的差值
  2. 随后让长的链表的头节点先走“差值“步,让他们站在同一起跑线
  3. 最后让他们携手同行,直到相遇,返回任意一个链表;若最终零个引用都为空,证明不相交,返回 null

代码解析

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {  
    //1. 计算两个链表的长度,并计算差值  
    int lenA = 0;  
    int lenB = 0;  
    ListNode curA = headA;  
    ListNode curB = headB;  
    while (curA != null) {  
        curA = curA.next;  
        lenA++;  
    }    
    while (curB != null) {  
        curB = curB.next;  
        lenB++;  
    }    
    int len = lenA - lenB;  
  
    curA = headA;  
    curB = headB;  
  
    //2. 根据差值,长的链表头节点先走len步,  
    // 让两个链表在同一起跑线  
    if (len > 0) {  
        int count = 0;  
        while (count != len) {  
            curA = curA.next;  
            count++;  
        }    
    } else {  
        int count = 0;  
        while (count != -len) {  
            curB = curB.next;  
            count++;  
        }    
    }  
    //3. 两个链表的节点携手同行,直到相等  
    while (curA != curB) {  
        curA = curA.next;  
        curB = curB.next;  
    }    
    if (curA == null) {  
        //若两个引用都为空,证明不相交  
        return null;  
    }    
    return curA;  
}

环形链表

141. 环形链表 - 力扣(LeetCode)
image.png|527

思路解透

  1. 定义两个节点,一个一次走一步,一个一次走两步
  2. 当走得快的节点不为空,并且走得快的节点的 next 不为空,循环就一直继续
  3. 当两个节点相等,则返回 true

假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况
因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

代码解析

public boolean hasCycle(ListNode head) {  
    ListNode fast = head;  
    ListNode slow = head;  
    while(fast != null && fast.next != null){  
        fast = fast.next.next;  
        slow = slow.next;  
        if(fast == slow)  
            return true;  
    }    
    return false;  
}

环形链表Ⅱ

142. 环形链表 II - 力扣(LeetCode)
image.png|528

思路解透

image.png|626

代码解析

public ListNode detectCycle(ListNode head) {  
    //1. 判断是否有环  
    ListNode fast = head;  
    ListNode slow = head;  
    while (fast != null && fast.next != null) {  
        fast = fast.next.next;  
        slow = slow.next;  
        //有环,跳出循环  
        if (fast == slow) {  
            break;  
        }    
    }    
    //若是因为没有环而跳出循环的话,返回null  
    if (fast == null || fast.next == null) {  
        return null;  
    }    
    //此时slow在相遇点,将fast拿到起始点  
    //让他们相向而行,相遇点即为入口点  
    fast = head;  
    while(fast != slow) {  
        fast = fast.next;  
        slow = slow.next;  
    }    
    return fast;  
}

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

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

相关文章

列表(list)—python

一、列表的定义方式 列表内的每一个数据称为元素&#xff0c;列表以[ ]作为标识&#xff0c;列表内的每个元素之间用逗号隔开。 列表的基本语法如下&#xff1a; #字面量 [元素1,元素2,元素3,元素4,……]#定义变量 变量名称[元素1,元素2,元素3,元素4,……]#定义空列表 变量名…

Linux的防火墙

一、防火墙概述 防火墙是一种计算机硬件和软件的结合&#xff0c;使internet和intranet之间建立一个安全网关&#xff08;Security Gateway&#xff09;&#xff0c;从而保护内网免受非法用户侵入的技术。 防火墙主要由服务访问规则、验证工具、包过滤和应用网关4个部分组成。…

安防视频监控EasyCVR视频汇聚平台无法编辑设备通道信息的原因排查及解决

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台基于云边端一体化架构&#xff0c;兼容性强、支持多协议接入&#xff0c;包括国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SD…

ECharts - 坐标轴刻度数值处理

写图表时&#xff0c;Y轴的数值过大&#xff0c;不太可能直接展示&#xff0c;这时候就得简写了&#xff0c;或者百分比展示的也要处理&#xff0c;如下图&#xff1a; yAxis: {type: value,// Y轴轴线axisLine: { show: false }, // 刻度线axisTick: { show: false },// 轴刻度…

ECharts实现按月统计和MTBF统计

一、数据准备 下表是小明最近一年的旅游记录 create_datecity_namecost_money2023-10-10 10:10:10北京14992023-11-11 11:11:11上海29992023-12-12 12:12:12上海19992024-01-24 12:12:12北京1232024-01-24 12:12:12上海2232024-02-24 12:12:12广州5642024-02-24 12:12:12北京…

学习笔记之Java篇(0729)

p 数组 大纲知识点数组的概念数组的定义、四个特点数组的常见操作普通遍历、for-each遍历、java.util.Array类用法多维数组多维数组的内存结构、存储表格、Javabean和数组存储表格常见算法冒泡排序基础算法、冒泡排序优化算法、二分法查找&#xff08;折半查找&#xff09; 1、…

【JavaWeb】Filter

基本使用 使用了过滤器之后&#xff0c;要想访问web服务器上的资源&#xff0c;必须先经过滤器&#xff0c;过滤器处理完毕之后&#xff0c;才可以访问对应的资源。过滤器一般完成一些通用的操作&#xff0c;比如&#xff1a;登录校验、统一编码处理、敏感字符处理等。 使用操…

nginx 子路径映射配置

如果子路径转发到另一个服务器IP&#xff0c;配置如下&#xff0c;注意都要以“/”结尾。 #指定nginx进程数 worker_processes 1; pcre_jit on;events {# 连接数上限worker_connections 30000; }#http服务 http {server {listen 20012;# 监听的端口号server_name localho…

Spring IoC DI(笔记)

一.了解SpringIoC&DI 1.1IoC 通过前面的学习,我们知道了Spring是一个开源框架,他让我们的开发更加简单.他支持广泛的应用场 景,有着活跃而庞大的社区,这也是Spring能够长久不衰的原因&#xff0c;但是这个概念相对来说,还是比较抽象&#xff0c;我们用一句更具体的话来概…

纯原创【车牌识别】基于图像处理的车牌识别——matlab项目实战(含GUI界面)详解

摘要 车牌识别系统乃计算机视觉与模式识别技术于智能交通领域的重要研究课题之一。其作用在于从复杂背景里提取运动中的汽车牌照&#xff0c;进而识别出车牌号码。车牌识别技术在高速公路电子收费、日常停车场管理以及交通违章监控等场景得到广泛运用。它的问世对于维护交通安全…

代码随想录二刷(链表章节)

代码随想录二刷(链表章节) 链表就是通过指针串联在一起的线性结构&#xff0c;每个节点都是由一个数据域和指针域(存放下一个节点的指针)。 双链表就是每个节点中既有指向前一个节点的&#xff0c;也有指向后一个节点的。 循环链表就是把头和尾连起来。 性能分析如下&#xf…

Java面试八股之@Autowired 和 @Resource的区别

Autowired 和 Resource的区别 在Spring框架中&#xff0c;Autowired 和 Resource 是两个常用的依赖注入注解&#xff0c;但它们有一些关键的区别。下面是这两个注解的主要差异&#xff1a; 1. 注解来源 Autowired&#xff1a; 是Spring框架提供的注解&#xff0c;位于包 or…

TerraSAR-XTanDEM-X卫星详解(一)

全球SAR卫星大盘点与回波数据处理专栏目录 1. TerraSAR-X简介 TerraSAR-X(Terra Synthetic Aperture Radar-X)和TanDEM-X(TerraSAR-X add-on for Digital Elevation Measurement)是由德国宇航中心(DLR)和EADS Astrium公司共同推出的一对双子卫星。Terra源自拉丁语,是地…

解决win10蓝屏“选择一个选项”的问题!

今天台式机开机&#xff0c;出现蓝屏问题&#xff0c;记录一下。 一、问题 启动修复不行&#xff0c;系统还原没还原点&#xff0c;系统映像恢复没有文件。难道要重装系统&#xff1f;手上只能Win7和XP的启动盘。此路不通。 二、解决 使用命令提示符。输入&#xff1a; bcdb…

《花100块做个摸鱼小网站! · 序》灵感来源

序 大家好呀&#xff0c;我是summo&#xff0c;这次来写写我在上班空闲(摸鱼)的时候做的一个小网站的事。去年阿里云不是推出了个活动嘛&#xff0c;2核2G的云服务器一年只要99块钱&#xff0c;懂行的人应该知道这个价格在业界已经是非常良心了&#xff0c;虽然优惠只有一年&a…

PMP考试难吗?好不好学?

PMP 并不难&#xff0c;虽然新考纲大家都说开盲盒&#xff0c;做阅读理解&#xff0c;但线上考试成绩出的快&#xff0c;晒 3A 的也不少。给大家分享下我的备考经历&#xff0c;希望能给后面备考的同学一点参考吧。 现在的新考纲是要学习三本书的&#xff0c;《PMBOK》第六版、…

弘景光电:技术实力与创新驱动并进

在光学镜头及摄像模组产品领域&#xff0c;广东弘景光电科技股份有限公司&#xff08;以下简称“弘景光电”&#xff09;无疑是一颗耀眼的明星。自成立以来&#xff0c;弘景光电凭借其强大的研发实力、卓越的产品性能、精密的制造工艺以及严格的质量管理体系&#xff0c;在光学…

使用 useSeoMeta 进行 SEO 配置

title: 使用 useSeoMeta 进行 SEO 配置 date: 2024/7/30 updated: 2024/7/30 author: cmdragon excerpt: 摘要&#xff1a;本文介绍了Nuxt3中的useSeoMeta组合函数&#xff0c;用于简化和优化网站的SEO配置。通过这个工具&#xff0c;开发者可以在Nuxt3项目中方便地设置页面…

C++ - 负载均衡式在线OJ

目录 一.项目的宏观结构 1.1 只实现类似 leetcode 的题⽬列表在线编程功能 1.2 项⽬宏观结构 1.3编写思路 二.所⽤技术与开发环境 2.1 所用技术 2.2 开发环境 三.compiler 服务设计 3.1 编译功能 3.2 日志功能 3.3 运⾏功能 3.4 编译并运⾏功能 3.5 把编译并运⾏功…

OpenBayes 教程上新 | 文生图、图生图、图像修复三合一神器, HiDiffusion 一键启动教程现已上线!

扩散模型已成为高分辨率图像合成的主流方法&#xff0c;传统的扩散模型虽然在图像合成方面取得了显著进展&#xff0c;但在扩展到更高分辨率时往往面临对象重复和计算成本增加的问题。 旷世科技开源的高分辨率框架 HiDiffusion&#xff0c;由分辨率感知 U-Net (RAU-Net) 和改进…