数据结构:LinkedList与链表—面试题(三)

news2025/1/10 0:55:11

目录

1、移除链表元素

2、反转链表

3、链表的中间结点

4、返回倒数第k个结点

 5、合并两个有序链表


1、移除链表元素

习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/remove-linked-list-elements/description/

描述:给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val ==      val 的节点,并返回 新的头节点 。

这道题大家看着是不是十分的眼熟,这其实就是我们在讲解无头单向链表时进行的一个方法的模拟实现

首先这道题我们要先进行头节点的判断如果头节点为空就代表链表为空,没有数据直接返回null

如果不为空,我们要创建两个指针,一个指向头结点(prev),一个指向头节点的下一个结点(cur),然后让cur不断的往前走,在走的过程中进行判断,如果cur的值不等于我们要删除的值就让prev移动到目前cur的位置,之后cur继续走如果cur的值等于我们要删除的数,居然prev的后继结点变成此时cur的后继结点,以达到删除结点的目的

完整代码

class Solution {
    public ListNode removeElements(ListNode head, int val) {
      if(head == null){
        return null;
      }
      ListNode cur = head.next;
      ListNode perv = head;
      while(cur != null){
        if(cur.val == val){
            perv.next = cur.next;
        }else{
            perv = cur;
        }
       cur = cur.next;
      }
      if(head.val == val){
        head = head.next;
      }
      return head;
    }
}

2、反转链表

习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/reverse-linked-list/description/

描述:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

首先我们依然要进行头结点的判断,但是这次我们又加了一个判断因为我们这次是要将一个链表进行反转,而当我们的链表只有一个数时,进行反转后的链表依旧跟原来一样,因此当头节点的下一个为空时即链表只有一个数,就直接返回头结点即可。

然后这次我们依然要创建一个指针指向头结点的下一个结点(cur),因为这次我们是反转链表我们的头节点将会变成最后一个结点,而最后有一个结点是没有后继结点的,因此我们要将头节点的后继置为空。

之后我们不断让cur往后走,并在循环中创建一个新的指向(curN)令他指向cur的下一个结点,这时我们让cur的下一个结点变成头节点,之后在将cur变成头节点,然后我们在让cur指针指向curN处,而进行新的循环时curN因为cur的改变会往后走一个结点这样就实现了cur的移动和链表的反转。

完整代码

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null){
            return null;
        }
        if(head.next == null){
            return head;
        }
        ListNode cur = head.next;
        head.next = null;
        while(cur != null){
            ListNode curN =cur.next;
            cur.next = head;
            head = cur;
            cur = curN;
        }
        return head;
    }
}

3、链表的中间结点

习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/middle-of-the-linked-list/description/描述:给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返            回第二个中间结点。

在这里我们用到了一个我们在做题时经常会使用到的一个方法:快慢指针。

所谓快慢指针其实就是让两个指针以同时移动但他们每次移动的距离是不同的这样就使得两个指针移动速度变得不同。

在这道题里我们使用的就是这种方法:首先我们设立两个指针,快指针(fast)和慢指针(slow)让他们指向头节点。

那么我们该怎样利用这两个指针找到中间结点呢?

我们来上面这两个事例,当这两个指针都在头节点时,我们让fast指针每次走两步,让slow指针每次走一步,当fast指针走到链表尽头时,即fast为空和fast的下一个结点为空时,结束移动,这时当我们结束移动后,会发现我们的slow指针正处于我们要找的中间结点位置

完整代码

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
}

4、返回倒数第k个结点

习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/kth-node-from-end-of-list-lcci/description/

描述:实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

对于这道题他让我们去求倒数第k个结点的值,在这里我们有一种方法来解决这个问题。

首先我们求出这个链表的长度,我们再用我们求出的长度减去k,这时根据得到的数,我们让一个指针从头结点走这个数的步,我们会发现最后停下的这个结点值正是倒数第k个结点的值。

完整代码

class Solution {
    public int kthToLast(ListNode head, int k) {
        ListNode cur = head;
         int count = 0;
        while(cur != null){
            count++;
            cur = cur.next;
        }
        ListNode fast = head;
        int n = count-k;
        while(n != 0){
            fast = fast.next;
            n--;
        }
        return fast.val;
    }
}

 5、合并两个有序链表

习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/merge-two-sorted-lists/description/描述:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所             有节点组成的。

在这里我们用到了一个我们经常使用的方法:创建一个虚拟头结点 

在这道题里我们先创建一个虚拟头结点node,在创建一个指针tmp指向虚拟头结点

我们发现这道题的要求是将两个升序链表合并为一个新的 升序 链表,所以我们需要进行大小的比较,因此在这里我们先创建一个循环,在循环中进行比较,让list1链表的值小于list2时就让tmp的后继变成这时list1,然后让list1往后走,反之就让tmp的后继变成这时list2,然后让list2往后走,并且,每比较一次就让tmp往后走一步,这样就成功实现了大小的比较和,两个链表的合并,但是这里我们需要注意一点,如果有一个链表先走完了,我们就可以让另一个链表剩下的值直接链接在tmp后边。最后返回从虚拟头节点的下一个结点返回链表,这时的链表就是我们新的 升序 链表

完整代码 

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode node = new ListNode(-1);
        ListNode tmp = node;
        while(list1 != null && list2 != null){
            if(list1.val < list2.val){
                tmp.next = list1;
                list1 = list1.next;
            }else{
                tmp.next = list2;
                list2 = list2.next;
            }
            tmp = tmp.next;
        }
         if(list1 == null){
                tmp.next = list2;
            }
            if(list2 == null){
                tmp.next = list1;
            }
        return node.next;
    }
}

6、分割链表

习题链接icon-default.png?t=O83Ahttps://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking描述:现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

首先我们创建两个虚拟头结点,并用两个指针指向他们,根据题目意思我们要将所有小于x的数放到一边,大于等于的放到另一边,并且不改变他们的顺序,这样的话我们利用排序肯定是不可以了,因此我们利用了虚拟头节点的办法,我们将小于x的放到一个链表当中,大于等于x的放到另一个链表中,最后在让这两个链表链接在一起,这样就成功的分割了链表

注意:在最后我们要将存放大于等于x的链表最后一个结点的后继如果不等于空就要置为空。

           如果小于x 的链表为空,我们可以直接返回大于等于x的链表。

 

完整代码

public class Partition {
    public ListNode partition(ListNode pHead, int x) {
       ListNode head1 = new ListNode(-1);
       ListNode head2 = new ListNode(-2);
       ListNode cur = head1;
       ListNode prev = head2;
       ListNode node = pHead;
       while(node != null){
          if(node.val < x){
             cur.next = node;
             cur = cur.next;
          }else{
             prev.next = node;
             prev = prev.next;
         }
           node = node.next;
        }
       cur.next = head2.next;
       if(head2.next != null){
         prev.next = null;
       }
       if(head1.next == null){
          return head2.next;
       }
       return head1.next;
    }
}

7、链表的回文结构 

习题链接icon-default.png?t=O83Ahttps://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking

描述:对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

根据题意我们直到我们要判断链表是否为回文链表,我们当为空和只有一个数时都是回文结构,因此要先进行判断,之后我直到回文结构代表链表一半和另一半的反转时相同的,因此我们发现这时我们上面讲的反转链表和求中间结点的结合,所以这题的思路就是找到中间结点,讲中间结点和之后的结点进行反转最后在与另一半进行比较每个结点的值如果出现一个不等就代表不是回文结构,如果另一个链表的下一个值,等于我们反转后最后一个值直接就可以范围true

完整代码

public class PalindromeList {
    public boolean chkPalindrome(ListNode A) {
        if(A == null || A.next ==null){
            return true;
        }
       ListNode fast = A;
       ListNode slow = A;
       while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
       }
       ListNode cur = slow.next;
       while(cur != null ){
        ListNode curN = cur.next;
        cur.next = slow;
        slow = cur;
        cur = curN;
       }
       while(A != slow){
         if(A.val != slow.val){
            return false;
         }
         if(A.next == slow){
            return true;
         }
         A = A.next;
         slow = slow.next;
       }
       return true;
    }
}

8、相交链表 

习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/intersection-of-two-linked-lists/

描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 

首先我们创建两个指针cur1和cur2,令他们分别指向head1和head2,这道题要我们判断两个链表存不存在相交结点,但是我们知道这两个可能长度是不相同的这就会导致在他们相交前是不一样长的因此,我们要先求出这两个链表的长度差,然后让长的链表先走差值步,令他们在同一个起跑线上,在一步一步的走,同时进行判断,如果走到最后都没有相等就代表没有相交

 

完整代码

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode cur1 = headA;
        ListNode cur2 = headB;
        int count1 = 0;
        while(cur1 != null){
            cur1 = cur1.next;
            count1++;
        }
        int count2 = 0;
        while(cur2 != null){
            cur2 = cur2.next;
            count2++;
        }
        cur1 = headA;
        cur2 = headB;
        int count3 = count1-count2;
        if(count3 < 0){
            cur1 = headB;
            cur2 = headA;
            count3 = count2 -count1;
        }
        while(count3 != 0){
            cur1 = cur1.next;
            count3--;
        }
        while(cur1 != cur2){
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        if(cur1 == null){//当走到最后链表会为空,但这时他们会相等,因此跳出循环,所以我们要先判 
                         //断是否是走到尽头引起的相等,如果是就返回null,如果不是就往下执行true
            return null;
        }
    return cur1;
    }
}

9、环形链表 

习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/linked-list-cycle/description/描述:

给你一个链表的头节点 head ,判断链表中是否有环。

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

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

这道题利用了快慢指针法,根据题意他要判断是否为环形链表,如果他是环形的话我们发现如果我们利用快慢指针,让一个指针一次走两步一个一次走一步,当慢指针进环的时候最好的情况下很快就会相遇,最坏的情况下是他们直接的距离是环的长度,但因为慢指针一次走一步快指针一次走两步,没动一次他们间的距离就会减少一步,因此他们一定会相遇,所以,如果他们相遇就代表有环,如果快指针走到最后为空就代表没有环

注意:当链表为空和只有一个结点时也是没有环的。

 

完整代码 

public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null){
            return false;
        }
        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;
    }
}

10、环形链表II

 习题链接icon-default.png?t=O83Ahttps://leetcode.cn/problems/linked-list-cycle-ii/description/

描述:

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

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

不允许修改链表。

这道题让我们去求环的入口点,首先我们来看下面这张图 

我们知道当我们进行环的判断时会有一个相遇点(M),我们假设入口点(E)到相遇点的距离为x,环的总长为R, 而链表的头结点到入口点的距离为L,根据上题我们知道两个指针在相遇前快指针可能已经走了n圈,所以快指针走的路程为L+x+nR,慢指针走的路程为L+x,而快指针是以慢指针的2倍前进的,因此他们相遇时快指针的的路程是慢指针的两倍,因此我们得出2*(L+x)=L+x+nR

当我们化简后发现L= nR-x,而我们的n取决于fast走的圈数,但是当我们以n=1来看时,我们发现L的长度就等于R-X(L=R-x是一定的,n的形成只是由于指针速度不同所导致的),这时我们发现如果有两个指针从头节点和相遇点一起走当他们相遇时的相遇结点就是我们的入口点

 

 完整代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null || head.next == null){
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
       while(fast != null && fast.next != null){
        fast = fast.next.next;
        slow = slow.next;
        if(fast == slow){
            break;
        }
       }
       if(fast == null || fast.next == null){
        return null;
       }
        fast = head;
       while(fast != slow){
        fast = fast.next;
        slow = slow.next;
       }
       return fast;
    }
}

好了今天的分享就到这里了,还请大家多多关注,我们下一篇见!

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

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

相关文章

QT实现 端口扫描暂停和继续功能 3

上篇QT给端口扫描工程增加线程2-CSDN博客 为按钮pushButton_Stop添加clicked事件&#xff0c;功能为暂停扫描&#xff0c;并在暂停后显示继续按钮&#xff0c;点击继续按钮之后继续扫描 1.更新UI 添加继续按钮 点击转到槽则会自动声明 2. 更新 MainWindow.h 需要新增的部分…

LabVIEW瞬变电磁接收系统

利用LabVIEW软件与USB4432采集卡开发瞬变电磁接收系统。系统通过改进硬件配置与软件编程&#xff0c;解决了传统仪器在信噪比低和抗干扰能力差的问题&#xff0c;实现了高精度的数据采集和处理&#xff0c;特别适用于地质勘探等领域。 ​ 项目背景&#xff1a; 瞬变电磁法是探…

左神算法基础巩固--3

文章目录 二叉树二叉树的遍历先序遍历中序遍历后序遍历 解答二叉树的宽度优先遍历 在这里插入图片描述 一颗完全二叉树具有以下特征&#xff1a;1.不存在任何一个节点具有右子树但不存在左子树.2.不存在任何一个节点在满足1的情况下左右子树不全且其后续节点不为叶子节点 根据以…

高山旅游景区有效降低成本,无人机山下到山上物资吊运技术详解

在高山旅游景区&#xff0c;传统的物资运输方式往往面临人力成本高昂、效率低下等问题&#xff0c;而无人机技术的引入为这一难题提供了新的解决方案。以下是对无人机从山下到山上进行物资吊运技术的详细解析&#xff1a; 一、无人机物资吊运技术的优势 1. 降低人力成本&#…

APP上架之Android 证书 MD5 指纹

Android 证书 MD5 指纹 1. 什么是 Android 证书 MD5 指纹&#xff1f; Android 证书 MD5 指纹是对证书数据进行 MD5 哈希运算后得到的 128 位字符串。在 Android 开发中&#xff0c;每个证书在理论上都有一个唯一的 MD5 指纹&#xff0c;用于识别和验证证书的有效性。证书指纹…

用户界面的UML建模11

然而&#xff0c;在用户界面方面&#xff0c;重要的是要了解《boundary》类是如何与这个异常分层结构进行关联的。 《exception》类的对象可以作为《control》类的对象。因此&#xff0c;《exception》类能够聚合《boundary》类。 参见图12&#xff0c;《exception》Database…

网络安全-XSS跨站脚本攻击(基础篇)

漏洞扫描的原理 1.跨站脚本攻击介绍 xss跨站脚本攻击&#xff1a; xSS 全称&#xff08;Cross site Scripting &#xff09;跨站脚本攻击&#xff0c;是最常见的Web应用程序安全漏洞之一&#xff0c;位于OWASP top 10 2013/2017年度分别为第三名和第七名&#xff0c;XSS是指攻…

CODESYS MODBUS TCP通信(禾川Q1 PLC作为MODBUS TCP从站)

禾川Q1 PLC MODBUS TCP 通信(PLC作为MODBUS TCP通信主站) 禾川Q1 PLC MODBUS TCP通信(CODESYS平台完整配置+代码)-CSDN博客文章浏览阅读28次。MATLAB和S7-1200PLC水箱液位高度PID控制联合仿真(MODBUSTCP通信)_将matlab仿真导入plc-CSDN博客文章浏览阅读722次。本文详细介绍了如…

golang OpcUaClient

实现功能 package mainimport ("fmt""log""opcuaclient/util/plugin/client/opcclient""os""os/signal""syscall" )func main() {OPCUATest()// 监听操作系统信号&#xff0c;阻塞直到接收到信号quit : make(chan…

git commit冲突,需输入提交信息合并提交

git commit时冲突&#xff0c;需输入提交信息合并提交&#xff0c;该如何操作&#xff1f; windows按esc键进入命令模式&#xff0c;输入&#xff1a;wq并按enter保存并退出即可。

Linux/Ubuntu/银河麒麟 arm64 飞腾FT2000 下使用 arm64版本 linuxdeployqt 打包Qt程序

文章目录 一、前言二、环境三、准备1、下载Linuxdeployqt源码2、下载Appimagetool-aarch64.AppImage四、编译linuxdeployqt1.配置环境变量2.编译linuxdeployqt五、安装patchelf六、配置Appimagetool七、打包Qt程序重要提示:测试启动应用八、其他九、最后一、前言 因为项目需要…

操作系统大题整理

专题一 程序代码题&#xff1a;程序设计与分析&#xff0c;主要考的是线程&#xff0c;多线程的并发&#xff1f; 大题第一问&#xff08;1&#xff09;操作系统的结构有哪几种常用的结构&#xff1f; 宏内核&#xff1a;宏内核是将操作系统的主要功能模块都集中在内核的一种结…

SQL编程语言

第一章 1. 数据库是长期储存在计算机内&#xff0c;由专门的数据管理软件(数据库管理系统)&#xff0c;进行统一组织和管理控制的大量数据的集合。 2.数据库的基本特点不包括可以快速检索。 3. 数据管理技术的发展经历了&#xff1a;人工管理阶段、文件系统阶段、数据库系统阶…

【跨域问题】

跨域问题 官方概念&#xff1a; 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域本质来说&#xff0c;是前端请求给到后端时候&#xff0c;请求头里面&#xff0c;有一个 Origin &#xff0c;会带上 协议域名端口号等&#xff1b;后端接受到请求&…

Linux(CentOS7)安装JDK和Maven

文章目录 CentOS软件安装方式JDK安装Maven安装 CentOS软件安装方式 安装方式特点二进制发布包安装软件已经针对具体平台编译打包发布&#xff0c;只要解压&#xff0c;修改配置即可。例如tomcatrpm(redhat package manager)安装软件已经按照redhat的包管理规范进行打包&#x…

RabbitMQ 可观测性最佳实践

RabbitMQ 简介 RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写&#xff0c;支持多种客户端。它通过使用交换机&#xff08;Exchanges&#xff09;、队列&#xff08;Queues&#xff09;和绑定&#xff08;Bindings&#xff09;来路由消息&#xff…

Github Copilot学习笔记

&#xff08;一&#xff09;Prompt Engineering 利用AI工具生成prompt设计好的prompt结构使用MarkDown语法&#xff0c;按Role, Skills, Constrains, Background, Requirements和Demo这几个维度描述需求。然后收输入提示词&#xff1a;作为 [Role], 拥有 [Skills], 严格遵守 […

单片机-定时器中断

1、相关知识 振荡周期1/12us; //振荡周期又称 S周期或时钟周期&#xff08;晶振周期或外加振荡周期&#xff09;。 状态周期1/6us; 机器周期1us; 指令周期1~4us; ①51单片机有两组定时器/计数器&#xff0c;因为既可以定时&#xff0c;又可以计数&#xff0c;故称之为定时器…

高比例压缩:Linux 中的压缩命令与技巧

文章目录 高比例压缩&#xff1a;Linux 中的压缩命令与技巧1. 压缩格式的选择2. gzip 命令示例&#xff1a;压缩文件示例&#xff1a;解压文件 3. bzip2 命令示例&#xff1a;压缩文件示例&#xff1a;解压文件 4. xz 命令示例&#xff1a;压缩文件示例&#xff1a;解压文件 5.…

【ArcGIS Pro二次开发实例教程】(1):图层的前置、后置

一、简介 此工具要实现的功能是&#xff1a;将内容框中当前选定的图层移到最顶层或最底层。 主要技术要点包括&#xff1a; 1、Config.daml文件设置&#xff08;UI设置&#xff09; 2、按钮的图片和位置设置 3、当前选定图层的获取 4、图层在内容列表中位置的获取和移动 …