链表题目专题

news2024/9/24 9:20:01

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

给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

非递归解决

这题让删除链表的倒数第n个节点,首先最容易想到的就是先求出链表的长度length,然后就可以找到要删除链表的前一个结点,让他的前一个结点指向要删除结点的下一个结点即可,这里就以示例为例画个图看一下

public ListNode removeNthFromEnd(ListNode head, int n) {
     ListNode pre = head;
	 // 获取要删除的倒数第N个节点
     int last = length(head) - n;
     //如果last等于0表示删除的是头结点
     if (last == 0)
         return head.next;
     //这里首先要找到要删除链表的前一个结点
     for (int i = 0; i < last - 1; i++) {
         pre = pre.next;
    }
    //然后让前一个结点的next指向要删除节点的next
    pre.next = pre.next.next;
    return head;
}

//求链表的长度
private int length(ListNode head) {
    int len = 0;
    while (head != null) {
        len++;
        head = head.next;
    }
    return len;
}

141. Linked List Cycle

快慢指针解决

判断链表是否有环应该是老生常谈的一个话题了,最简单的一种方式就是快慢指针,慢指针针每次走一步,快指针每次走两步,如果相遇就说明有环,如果有一个为空说明没有环。代码比较简单。

到这里问题好像并没有结束,为什么快慢指针就一定能判断是否有环。我们可以这样来思考一下,假如有环,那么快慢指针最终都会走到环上,假如环的长度是m,快慢指针最近的间距是n,如下图中所示

图片

快指针每次走两步,慢指针每次走一步,所以每走一次快慢指针的间距就要缩小一步,在图一中当走n次的时候就会相遇,在图二中当走m-n次的时候就会相遇。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        // 1、定义快慢指针
        ListNode fast,slow;
        // 2、定义快慢指针的初始位置
        fast=slow=head;
        // 3、定义快指针移动规则
        while(fast!=null&&fast.next!=null){
            // 快指针走两步
            fast=fast.next.next;
            // 慢指针走一步
            slow=slow.next;
            // 判断结果
            if(fast==slow){
                return true;
            }
        }
        return false;
    }
}

面试题 02.02. 返回倒数第 k 个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

双指针求解

这题要求链表的倒数第k个节点,最简单的方式就是使用两个指针,第一个指针先移动k步,然后第二个指针再从头开始,这个时候这两个指针同时移动,当第一个指针到链表的末尾的时候,返回第二个指针即可。

 public ListNode getKthFromEnd(ListNode head, int k) {
     ListNode first = head;
     ListNode second = head;
     //第一个指针先走k步
     while (k-- > 0) {
         first = first.next;
     }
     //然后两个指针在同时前进
     while (first != null) {
       first = first.next;
        second = second.next;
    }
    return second;
}

LCR 136. 删除链表的节点

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。

他表示的是删除链表中值等于val的结点,那么递归的终止条件就是当head等于空的时候,我们直接返回head,因为一个空的链表我们是没法删除的,也就是下面这样

if (head == null)    return head;

如果head结点不等于空,并且head结点的值等于val,我们直接返回head结点的下一个结点

if (head.val == val)    return head.next;

否则也就是说头结点是删不掉的,我们就递归调用,从头结点的下一个开始继续上面的操作,直到删除为止。

head.next = deleteNode(head.next, val);return head;

 递归实现如下: 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        // 单链表的头结点
         if(head==null){
             return null;
         }
         if(head.val==val){
            return head.next; 
         }
         // 其他情况就递归删除,从头结点的下一个节点开始,
         head.next=deleteNode(head.next, val);
         return head;
    }
}

  迭代实现如下:边界条件判断.

 public ListNode deleteNode(ListNode head, int val) {
     //边界条件判断
     if (head == null)
         return head;
     //如果要删除的是头结点,直接返回头结点的下一个结点即可
     if (head.val == val)
         return head.next;
     ListNode cur = head;
     //找到要删除结点的上一个结点
    while (cur.next != null && cur.next.val != val) {
        cur = cur.next;
    }
    //删除结点
    cur.next = cur.next.next;
    return head;
}

328. 奇偶链表

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

输入: head = [1,2,3,4,5]
输出: [1,3,5,2,4]

输入: head = [2,1,3,5,6,4,7]
输出: [2,3,6,7,1,5,4]

编码如下:注意这里需要使用几个变量,分别记录奇数链表的头节点和尾节点,偶数链表的头节点 和尾节点。

public ListNode oddEvenList(ListNode head) { 
   if (head == null || head.next == null) 
    {
	return head;
    } 	
    //奇数链表的头节点 
    ListNode oddHead = head; 
    //奇数链表的当前节点 
    ListNode oddCur = oddHead; 
    //偶数链表的头节点 
    ListNode evenHead = head.next; 
    //偶数链表的当前节点 
    ListNode evenCur = evenHead; 
    while (evenCur != null && evenCur.next != null) { 
        //奇数节点串一起 
        oddCur.next = oddCur.next.next; 
        //偶数节点串一起 
        evenCur.next = evenCur.next.next; 
        //奇偶指针往后移 
        oddCur = oddCur.next; 
        evenCur = evenCur.next; 
    } 
    //最后偶数链表和奇数链表需要串在一起 
    oddCur.next = evenHead; 
    return oddHead; 
}

876. 链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode fast=head;
        ListNode slow=head;
        // 定义快慢指针,一个快指针和一个慢指针,两个指针同时开始走,fast指针每次走两步,慢指针每次走一步
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        } 
        return slow;
    }
}

462. 找出两个链表的第一个公共节点

方法一:通过Set集合,第一个链表全部放入Set中,然后第二个集合进行判断是否存在.

public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 
     //创建集合set 
     Set<ListNode> set = new HashSet<>(); 
     //先把链表A的结点全部存放到集合set中 
     while (headA != null) { 
         set.add(headA); 
         headA = headA.next; 
     } 
  
    //然后访问链表B的结点,判断集合中是否包含链表B的结点,如果包含就直接返回 
    while (headB != null) { 
        if (set.contains(headB)) 
            return headB; 
        headB = headB.next; 
    } 
    //如果集合set不包含链表B的任何一个结点,说明他们没有交点,直接返回null 
    return null; 
}

方法二:我们还可以使用两个指针,最开始的时候一个指向链表A,一个指向链表B,然后他们每
次都要往后移动一位,顺便查看节点是否相等。如果链表A和链表B不相交,基本上没啥
可说的,我们这里假设链表A和链表B相交。那么就会有两种情况,
一种是链表A的长度和链表B的长度相等,他们每次都走一步,最终在相交点肯定会相
遇。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 
  //tempA和tempB我们可以认为是A,B两个指针 
  ListNode tempA = headA; 
  ListNode tempB = headB; 
  while (tempA != tempB) { 
  //如果指针tempA不为空,tempA就往后移一步。 
  //如果指针tempA为空,就让指针tempA指向headB(注意这里是headB不是tempB) 
  tempA = tempA == null ? headB : tempA.next; 
  //指针tempB同上 
  tempB = tempB == null ? headA : tempB.next; 
  } 
  //tempA要么是空,要么是两链表的交点 
  return tempA; 
} 

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

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

输入:head = [1,2,3,4]
输出:[2,1,4,3]
输入:head = []
输出:[]
输入:head = [1]
输出:[1]

 假如使用递归从第3个节点往后的节点全部两两交换了,这个时候我们可以把链表分为3 部分,第一个节点,第二个节点和后面交换完成的链表,就是1→2→3,这种形式,我 们只要再把1和2位置交换了。

class Solution {
    public ListNode swapPairs(ListNode head) {
         if(head==null||head.next==null){
            return head;
         }
        // 保存第三个节点
        //从第3个链表往后都交换完了,我们只需要交换前两个链表即可
         ListNode third=swapPairs(head.next.next);
        ListNode second=head.next;
        //这里我们把链表分为3组,分别是第1个节点,第2个节点,后面 
        head.next=third;
        second.next=head;
        return second;
    }
}

206. 反转链表

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
//每次访问的原链表节点都会成为新链表的头结点
public ListNode reverseList(ListNode head) { 
//新链表 
ListNode newHead = null; 
while (head != null) { 
//先保存访问的节点的下一个节点,保存起来 
//留着下一步访问的 
ListNode temp = head.next;
 //每次访问的原链表节点都会成为新链表的头结点, 
//其实就是把新链表挂到访问的原链表节点的 
//后面就行了 
head.next = newHead; 
//更新新链表 
newHead = head; 
//重新赋值,继续访问 
head = temp; 
} 
//返回新链表 
return newHead; 
} 

​​​​​​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 mergeTwoLists(ListNode l1, ListNode l2) {
        // 边界条件判定
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }
        // 按照单链表的方式,递归合并链表即可
        if (l1.val <= l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

234. 回文链表

通过双指针实现.

这题是让判断链表是否是回文链表,所谓的回文链表就是以链表中间为中心点两边对 称。我们常见的有判断一个字符串是否是回文字符串,这个比较简单,可以使用两个指 针,一个最左边一个最右边,两个指针同时往中间靠,判断所指的字符是否相等。反转上半个链表,再进行对比值。

 给你一个单链表的头节点 head ,请你判断该链表是否为

回文链表

。如果是,返回 true ;否则,返回 false 。

 

输入:head = [1,2,2,1]
输出:true
import java.util.*;
/**
 * 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 boolean isPalindrome(ListNode head) {
        List<Integer> vals = new ArrayList<Integer>();
        // 将链表的值复制到数组中
        ListNode currentNode = head;
        while (currentNode != null) {
            vals.add(currentNode.val);
            currentNode = currentNode.next;
        }
        // 使用双指针判断是否回文
        int front = 0;
        int back = vals.size() - 1;
        while (front < back) {
            if (!vals.get(front).equals(vals.get(back))) {
                return false;
            }
            front++;
            back--;
        }
        return true;
    }
}

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

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

相关文章

Hyper-v创建二代虚拟机无法进入bios问题解决

首先要确定从dvd驱动在上面&#xff0c;如果不在则把它向上移动然后保存。 启动虚拟机会进入下面界面 然后点下最左边的按钮然后疯狂点击f2(有的电脑是fnf2) 就可以顺利进入bios引导界面。

手机拯救计划:掌握3个技巧,轻松找回通讯录联系人号码

手机通讯录是我们的“社交地图”&#xff0c;一旦失去联系&#xff0c;就仿佛置身于茫茫人海中&#xff0c;不知所措。而安卓手机用户们&#xff0c;更是对通讯录的依赖达到了前所未有的高度&#xff0c;当发现它们丢失了&#xff0c;很容易产生焦虑情绪。别急&#xff0c;通过…

ARM架构(一)—— ARMV8V9基础概念

目录 1.ARMCore的时间线2.ARM术语小结2.1 A64和arrch642.2ARM架构现在的5个系列2.3 微架构2.4 PE2.5 Banked2.6 ARM文档术语2.7 IMPLEMENTATION DEFINFD 和 DEPRECATED2.8 EL1t和EL1h 3 ARMv7的软件架构4 安全状态切换模型4.1 Secure state和Non-secure state介绍 5 Interproce…

数据类型与结构设计:Rust 语言的深度探索

数据类型与结构设计&#xff1a;Rust 语言的深度探索 引言&#xff1a;数据与结构的精妙交响Rust 数据类型概览&#xff1a;坚实的基础数据类型详解基本数据类型&#xff1a;构建程序的原子单元复合数据类型&#xff1a;构建复杂数据结构的积木与结构体和枚举的结合 结构体与枚…

layui table template、或toolbar实现超出隐藏、更多展示全部效果

使用Layui table时&#xff0c;经常会使用template、或toolbar自定义模版属性。当使用该属性自定义HTML时&#xff0c;layui table 单元格原有的文本超出省略号隐藏功能&#xff0c;在该单元格讲不会生效。 前言&#xff1a;首先我们先搞懂layui超出隐藏原理&#xff0c;table单…

PHP微信小程序视频图文流量主变现小程序系统源码

&#x1f4b0;微信小程序新机遇&#xff01;视频图文流量主变现秘籍&#x1f511; &#x1f680;【流量变现新风口】&#x1f680; 还在为微信小程序的庞大流量如何转化为真金白银而苦恼吗&#xff1f;今天&#xff0c;就带你揭秘“微信小程序视频图文流量主变现小程序”的神…

mysql group_concat()函数、行转列函数

文章目录 一、group_concat函数1.1、语法1.2、示例1.2.1、查询所有姓名&#xff0c;并显示在一行1.2.2、单列合并&#xff0c;指定冒号分隔符1.2.3、单列合并&#xff0c;去重1.2.4、多列拼接合并1.2.5、多列拼接合并&#xff0c;列和列之间指定分隔符 在mysql的关联查询或子查…

十、Java集合 ★ ✔【泛型、通配符、List、Set、TreeSet、自然排序和比较器排序、Collections、可变参数、Map】

day05 泛型,数据结构,List,Set 今日目标 泛型使用 数据结构 List Set 1 泛型 1.1 泛型的介绍 ★ 泛型是一种类型参数&#xff0c;专门用来保存类型用的 最早接触泛型是在ArrayList&#xff0c;这个E就是所谓的泛型了。使用ArrayList时&#xff0c;只要给E指定某一个类型…

【Linux系统】信号的产生

信号 关于信号举一些生活中的例子 --- 比如交通指示灯... - 信号在生活中&#xff0c;随时可以产生 --- 信号的产生和我们是异步的&#xff01;&#xff08;异步的意思就是信号的产生和我没有直接关系&#xff09; - 你能认识这个信号 --- 我们知道这是信号&#xff0c;我们才…

C语言基础and数据结构

C语言程序和程序设计概述 程序:可以连续执行的一条条指令的集合 开发过程:C源程序(.c文件) --> 目标程序(.obj二进制文件,目标文件) --> 可执行文件(.exe文件) -->结果 在任何机器上可以运行C源程序生成的 .exe 文件 没有安装C语言集成开发环境,不能编译C语言程…

AES Android IOS H5 加密方案

前景&#xff1a; 1、本项目原有功能RSA客户端对敏感信息进行加密 2、本次漏洞说是服务端返回值有敏感信息&#xff0c;需要密文返回 方案&#xff1a; 本次方案不算完美&#xff0c;还是有被劫持篡改的风险&#xff0c;但基本https证书认证加持&#xff0c;风险相对较小 …

中介者模式(行为型)

目录 一、前言 二、中介者模式 三、总结 一、前言 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;又成为调停者模式&#xff0c;用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地互相引用&#xff0c;从而使其耦合…

颈动脉血管壁分割通过领域对齐、拓扑学习和稀疏标注中的Segment Anything模型在磁共振图像中的应用。

Title 题目 Carotid Vessel Wall Segmentation ThroughDomain Aligner, Topological Learning, andSegment Anything Model for Sparse Annotationin MR Images 颈动脉血管壁分割通过领域对齐、拓扑学习和稀疏标注中的Segment Anything模型在磁共振图像中的应用 01 文献速递…

基于AT89C51单片机的16×16点阵LED显示器字符滚动显示设计(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机的1616点阵LED显示器字符滚动显示设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 仿真效果图 仿真图 代码 系统论文 资源下载 设计的内容和要求 熟悉51系…

C语言 ——— 大/小端存储模式的介绍及判断

目录 何为大端小端 如何测试当前机器是大端还是小端 编写代码&#xff0c;判断当前机器的字节序 何为大端小端 大端字节序存储模式&#xff1a;数据的低位字节的内容 存放在 内存的高地址 中&#xff0c;数据的高位字节的内容 保存在 内存的低地址 中 小端字节序存储模式&am…

台达DVP系列串口驱动全面解析

1 驱动简介 台达DVP系列PLC&#xff08;包括ES2、SS、EX等&#xff09;使用串口通讯&#xff0c;外部设备可通过此口采集与PLC进行数据交互。网关使用台达DVP系列驱动&#xff0c;按照下述过程操作即可实现网关与PLC直接通讯 默认串口参数&#xff1a;9600/7/偶/1。 串口号&…

支持前端路由权限和后端接口权限的企业管理系统模版

一、技术栈 前端&#xff1a;iview-admin vue 后端&#xff1a;springboot shiro 二、基于角色的权限控制 1、路由权限 即不同角色的路由访问控制 2、菜单权限 即不同角色的菜单列表展示 3、按钮权限 即不同角色的按钮展示 4、接口权限 即不同角色的接口访问控制 三…

SQLMC:一款高性能大规模SQL注入安全扫描工具

关于SQLMC SQLMC是一款功能强大的高性能SQL注入安全扫描工具&#xff0c;该工具作为Kali Linux官方内置工具的其中一个部分&#xff0c;可以帮助广大研究人员检测目标域名的所有URL节点是否存在SQL注入问题。 该工具基于纯Python开发&#xff0c;适用于红队和蓝队成员&#xf…

path模块和HTTP协议

一。path模块常用API ./相对路径&#xff0c;/绝对路径 二&#xff0c;HTTP协议 1.请求报文 1.请求行 URL的组成 2.请求头 3.请求体 可以是空&#xff1a;GET请求 可以是字符串&#xff0c;还可以是json&#xff1a;POST请求 2.响应报文 1.响应行 HTTP / 1.1 200 OK H…

为什么讨厌Java的人比较多且易见?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「java的资料从专业入门到高级教程」&#xff0c;点个关注在评论区回复“666”之后私信回复“666”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;1. 我对OO理解的入门是从Java的…