相关算法---链表

常用算法整理:链表相关 链表的考点链表很多时候都是考察基本功,因为链表题大部分都不是很复杂,主要是对指针的操作,当然也有难的。 简单的题目包括 删除/插入节点、翻转、去重、排序等,难度高一些的题目依然是这些,不过会有一些条件,比如多个链表或者局部操作。对链表题的两个技巧: - 如果不确定最终结果的head,比如对两个链表进行排序,那么新建一个 dummy node。 - 可以通过快慢指针的方式取中间节点入门题:第一题 阅读详情

链表

1. 理论基础

链表就是指针串联在一起的线性结构,每个节点有数据域和指针域。链接的入口节点称为链表的头结点也就是head。

链表的类型:

  • 单链表
  • 双链表:每个节点都有两个指针域,一个指向下一个节点,一个指向上一个节点。向前、后都可以查询。
  • 循环链表:链表首尾相连。(可以解决约瑟夫环问题

链表在内存中不是连续分布的。

定义链表节点方式(做题会给出,但是自己要会写

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; }
  }

在做链表题时,最好都设置一个虚拟头节点来进行统一操作。

2. 移除链表元素

题目:给一个链表的头结点head和整数val,删除链表中等于给定值 val 的所有节点,并返回新的头结点。

题目分析:删除可能会涉及到头结点,所以可以设置一个虚拟节点来统一操作

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(null == head){
            return head;
        }

        //设置一个虚拟节点来进行统一操作
        ListNode dummy = new ListNode(-1, head);
        ListNode pre = dummy;
        ListNode cur = head;

        while(cur != null){
            if(val == cur.val){
                pre.next = cur.next;
            }else{
                pre = cur;
            }
            cur = cur.next;
        }
        return dummy.next; //这才是新的头结点
    }
}

3. 设计链表

题目:链表实现一些基本功能。

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

题目分析:自己选择设计单链表还是双链表。以下设置一个虚拟节点来统一操作。

class MyLinkedList {

    //单链表
    class ListNode{
        int val;
        ListNode next;
        ListNode(){}
        ListNode(int val){
            this.val = val;
        }
    }

    //size存储链表元素的个数
    int size;

    //虚拟头结点
    ListNode head;

    //初始化链表
    MyLinkedList(){
        size = 0;
        head = new ListNode(0);
    }

    //获取第index个节点的数值
    public int get(int index) {
        //如果index非法,返回-1
        if(index < 0 || index >= size){
            return -1;
        }

        ListNode cur = head;
        //包含一个虚拟头结点,所以查找第index + 1 个节点
        for(int i = 0; i <= index; i++){
            cur = cur.next;
        }
        return cur.val;
    }
    
    //在链表最前面插入一个节点
    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){
            return ;
        }

        if(index < 0){
            index = 0;
        }

        size++;

        //找到要插入节点的前驱
        ListNode pre = head;
        for(int i = 0; i < index; i++){
            pre = pre.next;
        }

        ListNode toAdd = new ListNode(val);
        toAdd.next = pre.next;
        pre.next = toAdd;
    }
    
    //删除第index个节点
    public void deleteAtIndex(int index) {
        if(index < 0 || index >= size){
            return ;
        }
        size--;
        ListNode pre = head;
        for(int i = 0; i < index; i++){
            pre = pre.next;
        }
        pre.next = pre.next.next;
    }
}

/**
 * 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);
 */

4. 反转链表

题目:反转一个单链表。

题目分析:cur指向头节点,pre初始化为null,cur->next指向pre,在这之前要把它保存下来。cur指向null,也就反转完成了,return pre即可。

//双指针方法(掌握住
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        
        //两个节点一定要初始化
        ListNode pre = null;
        ListNode temp = null;
        
        while(cur != null){
            temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
}

//递归方法(有点抽象 了解一下
class Solution {
    public ListNode reverseList(ListNode head) {
        return reverse(null, head);
    }

    private ListNode reverse(ListNode pre, ListNode cur) {
        if (cur == null) {
            return pre;
        }
        ListNode temp = null;
        temp = cur.next;// 先保存下一个节点
        cur.next = pre;// 反转
        // 更新prev、cur位置
        // prev = cur;
        // cur = temp;
        return reverse(cur, temp);
    }
}

// 从后向前递归
//没看懂 不太能理解(留着万一以后看懂了呢
class Solution {
    ListNode reverseList(ListNode head) {
        // 边缘条件判断
        if(head == null){
            return null;
        } 
        if (head.next == null){
            return head;
        }
        
        // 递归调用,翻转第二个节点开始往后的链表
        ListNode last = reverseList(head.next);
        // 翻转头节点与第二个节点的指向
        head.next.next = head;
        // 此时的 head 节点为尾节点,next 需要指向 NULL
        head.next = null;
        return last;
    } 
}

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

题目:给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

题目分析:画图理清楚操作的前后顺序。
在这里插入图片描述

//递归方法(好简便但是不太能理解
class Solution {
    public ListNode swapPairs(ListNode head) {
        //退出提交
        if(null == head || null == head.next){
            return head;
        }

        //获取当前节点的下一个节点
        ListNode after = head.next;
        //进行递归
        ListNode newNode = swapPairs(after.next);
        //进行交换
        after.next = head;
        head.next = newNode;

        return after;

    }
}

// 虚拟头结点
class Solution {
  public ListNode swapPairs(ListNode head) {

    ListNode dummyNode = new ListNode(0);
    dummyNode.next = head;
    ListNode prev = dummyNode;

    while (prev.next != null && prev.next.next != null) {
      ListNode temp = head.next.next; // 缓存 next
        //下面三个就对应了图上的三个步骤
      prev.next = head.next;          // 将 prev 的 next 改为 head 的 next
      head.next.next = head;          // 将 head.next(prev.next) 的next,指向 head
      head.next = temp;               // 将head 的 next 接上缓存的temp
      prev = head;                    // 步进1位
      head = head.next;               // 步进1位
    }
    return dummyNode.next;
  }
}

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

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

题目分析:双指针的经典应用:设置一个dummy,fast和slow都指向它。fast先走n + 1步,直到fast.next == null,则slow此时为要删除节点的前驱。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        ListNode fast = dummy;
        ListNode slow = dummy;
        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 dummy.next;
    }
}

7. 链表相交

题目:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。注意:函数返回结果后,链表必须 保持其原始结构 。

题目分析:求两个链表交点节点的指针,是指针相等而不是数值相等。步骤:求出两个链表的长度,缩短差值让其两个链表指针对齐,这样再开始比较是否相同。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB;
        int lenA = 0, lenB = 0;
        //求链表A的长度
        while(curA != null){
            lenA++;
            curA = curA.next;
        } 
        //求链表B的长度
        while(curB != null){
            lenB++;
            curB = curB.next;
        } 

        curA = headA;
        curB = headB;

        //指定curA是最长链表的头结点,LenA是最长链表的长度
        if(lenB > lenA){
            //交换长度
            int temp = lenA;
            lenA = lenB;
            lenB = temp;

            //交换节点
            ListNode tempNode = curA;
            curA = curB;
            curB = tempNode;
        }
        //长度差
        int gap = lenA - lenB;

        //让两个指针对齐
        while(gap-- > 0){
            curA = curA.next;
        }

        //遍历,有相同节点就返回
        while(curA != null){
            if(curA == curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

8. 环形链表||

题目:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

题目分析:

  • 判断是否有环:快慢指针,fast走两步,slow走一步,最后相遇就表明有环。
  • 有环怎么找到环的入口:结论:从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
public class Solution {
    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;
    }
}
Python爬虫技术应用:体育赛事直播数据抓取与分析 Web爬虫(Web Crawling)是一种通过模拟浏览器行为从网站获取数据的技术。发送请求:发送HTTP请求(通常是GET或POST请求)获取目标网页的HTML内容。解析网页:使用解析工具(如lxml)从HTML中提取出所需要的信息。存储数据:将抓取到的数据存储到数据库、文件或数据结构中,供后续分析和使用。数据分析与展示:使用数据分析工具(如PandasMatplotlib)对数据进行处理、清洗和可视化,生成有价值的报告和图表。Requests:用于发送静态网页的HTTP请求并获取响应。 阅读详情

相关推荐

医疗器械软件测试输出内容(1)

*单元测试(Unit Testing):**单元测试是软件测试的最底层,用于验证软件中最小的可测试单元——函数、方法或模块。系统测试是在集成测试之后进行的,它对整个系统进行测试,验证系统在不同部分集成在一起后是否满足需求和规格。: 集成测试是在单元测试之后进行的,它关注不同单元之间的交互和集成。对于不同安全级别的软件(IEC 62304 A类、B类、C类),在体系上要求输出的文件内容有所区别。**说明:**将集成测试和软件系统测试合并为一项单一的计划和一组活动是可接收的。

ct745363083的博客 1867

链表相关算法汇总(详细)

链表基础知识 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(log

泛泛之素 8482

角谱迭代与傅里叶变换迭代算法(GS)的原理及其实例演示分析

角谱迭代与傅里叶变换迭代算法(GS)的原理及其实例演示分析 目前,迭代法和强度传输方程(TIE)法是两类典型的非干涉相位检索技术(Phase Retrieval,被称为相位恢复、相位检索、相位反演法、相位复原等)。迭代法中的经典算法是Gerchberg-Saxton(GS),随后,出现了包括错误减少算法(ER)、混合输入输出法(HIO)、梯度搜索算法、角谱迭代算法等改进算法。...

简单光学 2万+

链表相关算法

大道无形

weixin_41297594的博客 1160

python解析通达信dat与blk数据文件【附源码】

本文介绍了一个完整的通达信金融数据解析器项目,该项目攻克了通达信专有二进制文件格式解析的技术难题。项目采用模块化架构,从基础二进制解析到增强数据分类,最终实现智能语义化列名生成,形成完整的数据处理链路。核心技术包括自适应编码检测、智能数据类型推断和基于业务规则的语义化处理,解决了逆向工程、多编码兼容性等挑战。项目成果显著,解析成功率达100%,数据可读性大幅提升,开发效率提高50%,为量化交易、可视化分析等场景提供了可靠数据支持。该方案不仅具备技术创新性,更具有实际工程应用价值,为金融数据分析领域提供了可复

qq_36224726的博客 2690

STM32F407 CubeMX UART DMA高效解析BNO085九轴数据

本文详细介绍了如何在STM32F407平台上使用CubeMX配置UART和DMA高效解析BNO085九轴传感器数据。通过DMA循环接收机制实现低CPU占用的实时数据采集,并分享数据解析技巧、错误处理及实战调试经验,为嵌入式开发者提供完整解决方案。

o4p5q6r7s的博客 236

算法:链表

链表(Linked List)是最简单的线性的、动态数据结构。理解它是理解树结构、图结构的基础。链表在插入数据的时候可以达到 O(1) 的复杂度,但是查找一个节点或者访问特定编号的节点则需要 O(n) 的时间。

Elson的博客 938

Unity接入Google登录:Credential Manager完整集成指南与避坑实践

在移动应用开发中,第三方登录是提升用户体验和降低注册门槛的关键技术。其核心原理是通过OAuth 2.0等授权协议,安全地获取用户在平台的身份凭证。对于面向海外市场的Unity应用,Google登录因其庞大的用户基数成为首选方案。然而,随着Android系统更新和隐私政策收紧,传统的WebView登录方式面临兼容性挑战。Credential Manager作为Google推出的现代化凭据管理API,通过系统级集成解决了这一问题,它统一了密码、通行密钥和第三方登录的调用接口,显著提升了登录成功率和原生体验。在U

weixin_28025327的博客 320

链表——基本算法

1、反转链表 给出3个指针,一个cur,用于遍历链表中的每个节点,一个prev,用于保存cur指向的节点的上一个节点地址,还有一个after,用于保存cur指向的节点的下一个节点地址,链表操作遵循先连后断,即 ...

sy2453的博客 2283

【AutoSar CP】SoAd模块

比如对于特定的PDU,其PduId在程序编译时就确定了,但是在代码运行中,该PduId可能需要发送到不同的远端ip,这时就需要用SoAd来设置连接远端地址信息。SoAdSocketConnectionGroup(连接参数)SoAdSocketRoute(接收数据)SoAdRoutingGroup(开关)SoAdPduRoute(发送数据)

至道无难,唯嫌拣择。 1689

STM32F407VET6与CH395Q串口通信实战:从零搭建以太网客户端(附完整代码)

本文详细介绍了基于STM32F407VET6微控制器与南京沁恒微CH395Q以太网芯片,通过串口通信从零搭建TCP客户端应用的完整实战过程。内容涵盖硬件连接、驱动层设计、基于FreeRTOS的任务实现以及核心调试技巧,并提供了完整的代码示例,帮助嵌入式开发者快速实现设备联网功能。

weixin_29179311的博客 416

【数据结构-链表】链表的相关算法

【数据结构-链表】链表的相关算法

Mount256的博客 1399

基于Vivado MIG IP核的DDR3读写实验(top_rom_ddr/ddr_top)

一、前言 关于Vivado MIG IP核详细配置可以参考我之前的文章:基于Vivado MIG IP核的DDR3控制器(DDR3_CONTROL) 关于MIG IP核的用户端的接口时序可以参考这篇文章:XILINX 的 MIG IP(非AXI4)接口时序以及控制 二、实验内容 本次实验的内容主要是通过MIG IP核向DDR3读写数据,DDR3的接口时序由ddr_top模块提供: ddr_top模块的数据来源是wr_fifo,wr_fifo的数据实际来自top_sd_photo模块(本实验仿真

耐心的小黑的博客 3027

链表相关算法总结

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。因为在编写程序时,经常用来评估代码能力--包括代码规范性、完整性、鲁棒性。 本文按照论文按照题目进行距离总结,题目列表如下: 1、环形链表插值问题 2、当前访问节点删除问题 3、链表中荷兰国旗问题 4、**单链表的k区间逆序问题 5、复杂结构链表的复制 6、单链表判断是否有环

victor的博客 2954

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【LeetCode】链表相关算法题

链表是一种基础而强大的线性数据结构,其核心思想是通过节点和指针构建数据序列。与数组不同,链表中的元素在内存中非连续存储,每个节点包含数据和指向下一节点的指针。

qq_45795794的博客 459

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

常见链表专题相关算法

LeetCode相关刷题

我要学编程的博客 1296

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

反转链表及相关算法题

反转链表是链表的一个常用操作,一些算法题中也需要用到此操作,是值得学习探讨的。 1 反转链表 剑指 Offer 24. 反转链表 题目描述:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 涉及到链表的操作,我们可以先在纸上画出过程,写程序时思路会更清晰 根据以上图解,思路主要为两个步骤循环操作: 将当前节点next

weixin_49555177的博客 235

链表-相关面试算法题

从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。在 B 中,相交节点前有 1 个节点。

渴望飞翔的小白 1161

详解链表相关算法

链表(linked list)是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。[算法导论链表相关的题解](https://walkccc.me/CLRS/Chap10/10.2/)。本文将从概念,基础算法,常见题目等方面进行陈述。

LynnWonder 599

顺序表,链表,栈所有相关算法题

1.询问学号【题⽬描述】有 n(n<=2e6)名同学陆陆续续进⼊教室。我们知道每名同学的学号(在1 到 1e9之间),按进教室的顺序给出。上课了,⽼师想知道第 个进⼊教室的同学的学号是什么(最先进⼊教室的同学i = 1 ),询问次数不超过 1e5次。【输⼊描述】第⼀⾏2个整数n和m,表⽰学⽣个数和询问次数。第⼆⾏n个整数,表⽰按顺序进⼊教室的学号。第三⾏m个整数,表⽰询问第⼏个进⼊教室的同学。【输出描述】输出m个整数表⽰答案,⽤换⾏隔开。

w1114waini的博客 2188

【算法系列篇】与链表相关的算法

与链表相关的算法:两数相加、两两交换链表中的节点、重排链表、合并 k 个升序链表、k 个一组翻转链表

不能再留遗憾了的博客 1998

单向链表的理解及相关算法

让p指向头结点的下一结点,并将链表头结点置空,q指向p->next,遍历链表,先将p->next保存在q中,再将其头插到head中,将保存的地址q重新赋值给p,循环上述过程,直到p指向nullptr退出循环,完成了单链表逆序。先创建一个指针指向头结点,遍历链表,让头节点指向它的下一个结点,回收p指向的内存空间,此时p就成了野指针,需要将其重新指向头结点,直到p为nullptr时,循环结束。这里删除后,不直接return,而是将p重新指向q指向的结点的下一个结点,否则p为野指针,继续操作会导致程序崩溃。

d6d4664948的博客 569

【算法笔记】链表相关的题目

单向链表是非常考验编码水平的一类题目,很多时候感觉很简单的算法,在指针上一不注意,就会出现各种意想不到的问题,所以对于这类题目,要思路清晰,定义好变量和之间的关系。今天梳理几个链表相关的题目。

u012559967的专栏 859

【算法】链表相关算法题

同时遍历两个链表,取 val 小的那个节点尾插到新链表中。

m0_51064412的博客 1166

【基础算法】链表相关题目

系列综述:💞目的:本系列是个人整理为了秋招算法的,整理期间苛求每个知识点,平衡理解简易度与深入程度。🥰来源:材料主要源于代码随想录进行的,每个算法代码参考leetcode高赞回答和其他平台热门博客,其中也可能含有一些的个人思考。

qq_43840665的博客 843

链表、栈相关算法题

解法:使用队列实现,将根节点入队,然后在循环中,每次取出队列头部节点进行访问,并将其左子节点和右子节点(如果存在)依次入队,当一层的节点全部处理完后,记录当前层的节点值,直到队列为空,即可得到二叉树的层次遍历结果。迭代法:使用栈模拟递归过程,先将根节点入栈,然后循环取出栈顶节点,访问该节点后将其右子节点、左子节点(注意顺序)依次入栈,直到栈为空。迭代法:利用栈,先将根节点的所有左子节点依次入栈,然后取出栈顶节点进行访问,再将其右子节点入栈并重复上述过程,直到栈为空。二叉树的深度遍历(后序遍历)

m0_64616651的博客 408
上一篇: 相关算法---数组
下一篇: 相关算法---哈希表
ZoeLandia
博客等级 码龄6年 734粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值