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

系列综述:
💞目的:本系列是个人整理为了秋招算法的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料主要源于代码随想录进行的,每个算法代码参考leetcode高赞回答和其他平台热门博客,其中也可能含有一些的个人思考。
🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!
🌈数据结构基础知识总结篇


文章目录

    • 一、链表理论基础
      • 链表的定义
      • 移除链表元素
      • 实现链表相关函数
    • 二、双指针
      • 反转链表
      • 交换相邻链表节点
      • 删除链表的倒数第 N 个结点
      • 链表相交
      • 链表相交
    • 参考博客


😊点此到文末惊喜↩︎


一、链表理论基础

链表的定义

  1. 单链表数据结构
    • 链表由下一个节点指针组成
    • 成员初始化构造函数,如果不定义,C++也会进行默认生成
    struct listNode{
    	int val;
    	listNode *next;
    	listNode(int x):val(x), next(NULL){}
    }
    

移除链表元素

  1. 链表基本操作
    • 添加虚拟头节点vHead,统一遍历操作。
    • 删除链表中的节点,不要忘记delete释放
  2. 题目
    在这里插入图片描述
    	/**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode() : val(0), next(nullptr) {}
     *     ListNode(int x) : val(x), next(nullptr) {}
     *     ListNode(int x, ListNode *next) : val(x), next(next) {}
     * };
     */
    ListNode* removeElements(ListNode* head, int val) {
        // 定义虚拟头节点
        ListNode *vHead = new ListNode(0, head);
        ListNode* cur = vHead;// 定义工作指针cur
        while(cur->next != nullptr){
            if(cur->next->val == val){// 为了获取操作节点的前一个节点进行删除
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            }else{
                cur = cur->next;// 工作指针++
            }
        }
        // 删除头节点
        head = vHead->next;
        delete(vHead);
        return head;
    }
    

实现链表相关函数

  1. 相关题目

实现 MyLinkedList 类:

  • MyLinkedList() 初始化 MyLinkedList 对象。
  • int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
  • void addAtHead(int val) 将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  • void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  • void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  • void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。
class MyLinkedList {
public:
	// 定义链表节点
    struct LinkNode{
        int val;
        LinkNode *next;
        LinkNode(int val):val(val),next(nullptr){}
    };

	// 初始化头节点
    MyLinkedList() {
        vHead = new LinkNode(0);
        size = 0;
    }
    // 根据索引值获取对应节点值
    int get(int index) {
        if(index < 0 || index > (size-1)) 
            return -1;
        // *****带头节点的索引值定位********
        LinkNode* cur = vHead->next;
        while(index--){
            cur = cur->next;
        }
        // ************************************
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkNode* node = new LinkNode(val);
        node->next = vHead->next;
        vHead->next = node;
        ++size;
    }
    
    void addAtTail(int val) {
        LinkNode* node = new LinkNode(val);
        LinkNode *cur = vHead;
        while(cur->next != nullptr){
            cur = cur->next;
        }
        cur->next = node;
        ++size;
    }
    
    void addAtIndex(int index, int val) {
        if(index > size) return;
        if(index < 0) index = 0;
        LinkNode* node = new LinkNode(val);
        LinkNode* cur = vHead;
         while(index--){
            cur = cur->next;
        }
        node->next = cur->next;
        cur->next = node;
        size++;

    }
    
    void deleteAtIndex(int index) {
        if(index < 0|| index >= size) 
            return ;
        LinkNode *cur = vHead;
        while(index--){
            cur = cur->next;
        }
        LinkNode *tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        size--;


    }

    private:
        LinkNode *vHead;// 首地址
        int size;// 大小
};

二、双指针

反转链表

  1. 头插法可以进行链表的反转
    • 尽量使用明确的逻辑关系,减少变量的转换
    • 先进行状态变量的状态保存,后进行逻辑处理
    ListNode* reverseList(ListNode* head) {
            if(head == nullptr)
                    return nullptr;
            // 头插法
            ListNode* vHead = new ListNode(0); // 虚拟头节点
            // 被遍历链表的工作指针
            ListNode* cur = head;
            ListNode* hind;
           // 开始遍历
            while(cur!= nullptr){
                hind = cur->next;// 一定要确切的使用逻辑关系
                // 头插法
                cur->next = vHead->next;
                vHead->next = cur;
                cur = hind;   
            }
            return vHead->next;
        }
    

交换相邻链表节点

  1. letcode题目网址
    在这里插入图片描述
    ListNode* swapPairs(ListNode* head){
    	// 健壮性检查
    	if(head == nullptr)
    	    return nullptr;
    	
    	// 指向操作节点组的第一个和第二个
    	ListNode* prior_first;
    	ListNode* prior_second;-
    	// 增加虚拟头节点
    	ListNode* vHead = new ListNode(0);
    	vHead->next = head;
    	ListNode *cur = vHead;
    	while(cur->next != nullptr && cur->next->next != nullptr){
    	    prior_first = cur->next;
    	    prior_second = cur->next->next;
    	    prior_first->next = prior_second->next;
    	    prior_second->next = prior_first;
    	    cur->next = prior_second; 
    	    cur = prior_second->next;// cur指向被操作节点组的前一个
    	}
    	return vHead->next;
    }
    

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

  1. letcode题目
    在这里插入图片描述
    ListNode* removeNthFromEnd(ListNode* head, int n) {
    	if(n < 0 || head == nullptr)
    	    return nullptr;
    	// 快慢指针拉开n个节点的距离
    	ListNode *vHead = new ListNode(0);
    	vHead->next = head;
    	ListNode *slow = vHead;
    	ListNode *fast = vHead;
    	// 让slow指向被删除节点的前一个
    	while(n--){
    	    fast = fast->next;
    	}
    	// 同步移动
    	while(fast->next != nullptr){
    	    fast = fast->next;
    	    slow = slow->next;
    	}
    	// 删除节点
    	slow->next = slow->next->next;
    	
    	return vHead->next;
    }
    

链表相交

  1. letcode题目链接
    在这里插入图片描述
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *curA = headA;
        ListNode *curB = headB;
        
        int lenA = 0;
        int lenB = 0;
        // 计算A和B的长度
        while(curA != nullptr){
            lenA++;
            curA = curA->next;
        }
        while(curB != nullptr){
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        // 求两链的差距
        int dis = 0;
        if(lenA > lenB){
            dis = lenA-lenB;
            while(dis--){
                curA = curA->next;
            }
        }else{
            dis = lenB-lenA;
            while(dis--){
                curB = curB->next;
            }
        }
    
        // 同步移动判断指针
        while(curA != curB){
            if(curA == nullptr || curB == nullptr){
                return nullptr;
            }
            curA = curA->next;
            curB = curB->next;
        }
    
        return curA;
    }
    
  2. 有点东西的写法
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
            ListNode *A = headA, *B = headB;
            // 核心在于交换头节点
            while (A != B) {
                A = A != nullptr ? A->next : headB;
                B = B != nullptr ? B->next : headA;
            }
            return A;
        }
    

链表相交

  1. letcode题目链接
    • 一个节点的next是否能访问,需要判断该节点是否存在
    • 只写容易判断的逻辑,其他的交给else
    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){
                slow=head;
                while(slow!=fast){
                    slow=slow->next;
                    fast=fast->next;
                }
                return fast;
            }
        }
        return NULL;
     }
    


少年,我观你骨骼清奇,颖悟绝伦,必成人中龙凤。
不如点赞·收藏·关注一波


🚩点此跳转到首行↩︎

参考博客

  1. 代码随想录
  2. letcode

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

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

相关文章

官宣|Apache Flink 1.17 发布公告

Apache Flink PMC&#xff08;项目管理委员&#xff09;很高兴地宣布发布 Apache Flink 1.17.0。Apache Flink 是领先的流处理标准&#xff0c;流批统一的数据处理概念在越来越多的公司中得到认可。得益于我们出色的社区和优秀的贡献者&#xff0c;Apache Flink 在 Apache 社区…

STM32F407控制微型推拉式电磁铁(通过继电器)

1、继电器 继电器相当于开关&#xff0c;单片机通过io口高低电平的控制来控制继电器的开闭。采用继电器的好处除了能够用低电压控制高电压&#xff08;如32单片机控制220V的电压&#xff09;外&#xff0c;还可以防止电流反冲&#xff0c;弄烧单片机。 本文采用3.3v的电磁铁&am…

三、MyBatis核心配置文件详解

核心配置文件中的标签必须按照固定的顺序(有的标签可以不写&#xff0c;但顺序一定不能乱)&#xff1a; properties、settings、typeAliases、typeHandlers、objectFactory、objectWrapperFactory、reflectorFactory、plugins、environments、databaseIdProvider、mappers 一、…

b01lers(php.galf)

目录 前文 正文 前文 <?phpclass A{public $codeNULL;public $argsNULL;public function __construct($code,$argsNULL){$this->code$code;$this->args$args;print_r("2333") ;} public function __invoke($code,$args){echo $code;print_r("执行inv…

记一次若依后台管理系统渗透

前言 最近客户开始hw前的风险排查&#xff0c;让我们帮他做个渗透测试&#xff0c;只给一个单位名称。通过前期的信息收集&#xff0c;发现了这个站点&#xff1a; 没有验证码&#xff0c;再加上这个图标&#xff0c;吸引了我注意&#xff1a; 从弱口令开始 若依默认口令为ad…

Android 12.0 Settings主页面去掉FocusRecyclerView相关功能

1.前言 在12.0的系统rom产品定制化开发中,在系统Settings主页面的主菜单中,在测试某些功能的时候,比如开启护眼模式和改变系统密度会在主菜单第一项的网络菜单头部增加 自定义您的设备和设置护眼模式时间安排 等等相关的设置模块 这对于菜单布局显示相当不美观,所以根据系…

机器学习---降维算法

知其然知其所以然【写在前面】主成分分析&#xff08;PCA&#xff09;原理部分代码部分可视化部分线性判别分析&#xff08;LDA&#xff09;原理部分代码部分可视化部分独立成分分析&#xff08;ICA&#xff09;原理部分代码部分可视化部分t-SNE降维算法原理部分代码部分可视化…

请求响应数据?Controler层注解!

目录1. 请求1.1概述1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象1.4 数组集合参数1.4.1 数组1.4.2 集合1.5 日期参数1.6 JSON参数1.7 路径参数2. 响应2.1 ResponseBody2.2 统一响应结果1. 请求 1.1概述…

Hive数据仓库简介

文章目录Hive数据仓库简介一、数据仓库简介1. 什么是数据仓库2. 数据仓库的结构2.1 数据源2.2 数据存储与管理2.3 OLAP服务器2.4 前端工具3. 数据仓库的数据模型3.1 星状模型3.2 雪花模型二、Hive简介1. 什么是Hive2. Hive的发展历程3. Hive的本质4. Hive的优缺点4.1 优点4.2 缺…

Vue2响应式原理

目录 Object.defineProperty() 监听对象中的简单数据类型 监听对象中的对象(可以深层) 监听对象中的数组 借鉴的帖子&#xff1a;Object.defineProperty方法&#xff08;详解&#xff09;_objectdefineproperty_搞前端的小菜的博客-CSDN博客 b站视频讲解&#xff1a;Vue2响…

学习 Python 之 Pygame 开发魂斗罗(十三)

学习 Python 之 Pygame 开发魂斗罗&#xff08;十三&#xff09;继续编写魂斗罗1. 创建敌人2类2. 编写敌人2类的draw()函数3. 编写敌人越界消失函数4. 编写敌人开火函数5. 把敌人2加入地图进行测试继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗&#xff08;十…

Adapter基础讲解

这一节我们要讲的UI控件都是跟Adapter(适配器)打交道的,了解并学会使用Adapter很重要, Adapter是用来帮助填充数据的中间桥梁,简单来说就是:将各种数据以合适的形式显示到view上,提供 给用户看! 1.MVC模式的简单理解 在开始学习Adapter之前我们要来了解下这个MVC模式概…

SpringBoot——Mybatis-XML映射文件—动态SQL

使用XML映射文件配置SQL语句的规范 XML文件当中的Mapper标签里面使用的select标签的id属性是Mapper接口里面的方法名&#xff0c;resultType属性名是SQL语句要返回的对象类型。 MybatisX插件 用于管理接口方法和映射文件的关系 注解和XML配置SQL语句两种选择 动态SQL——w…

Cookie 和 Session的区别

文章目录时间&#xff1a;2023年3月23日第一&#xff1a;什么是 Cookie 和 Session ?什么是 Cookie什么是 Session第二&#xff1a;Cookie 和 Session 有什么不同&#xff1f;第三&#xff1a;为什么需要 Cookie 和 Session&#xff0c;他们有什么关联&#xff1f;第四&#x…

由本溯源,带你探索BI实时性的本质

BI 采用T1模式 BI的数据仓库架构本身就决定了对数据的实时性要求没有那么高&#xff0c;ETL的过程不可或缺&#xff0c;Extraction 抽取、Transformation 转换、Loading 加载&#xff0c;这三个环节本身就是有时间损耗的。 BI - 派可数据BI可视化分析平台 首先&#xff0c;Ex…

动态内存管理(上)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是动态内存管理噢&#xff0c;下面&#xff0c;让我们进入动态内存管理的世界吧 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 为什么存在动态内存分配 我们已…

第十四届蓝桥杯三月真题刷题训练——第 22 天

目录 第 1 题&#xff1a;受伤的皇后_dfs 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码&#xff1a; 思路&#xff1a; 第 2 题&#xff1a;完全平方数 问题描述 输入格式 输出格式 样例输入 1 样例输出 1 样例输入 2 样例输出 2 评测用例规模与约…

Jenkins--邮件通知设置与构建日志邮件通知设置(踩过很多坑之后,记录一下)

1为啥要配置邮件通知配置邮件通知的目的是为了给用户发送构建结果的状态&#xff0c;以便用户知晓构建任务后的结果。2 开始配置邮件通知2.1 插件准备先检查Jenkins是否安装了Email Extension Plugin 插件&#xff0c;检查方法如下&#xff1a;进入Jenkins-->Manage Jenkins…

uni-app:登录与支付--用户信息

用户信息 实现用户头像昵称区域的基本布局 在 my-userinfo 组件中&#xff0c;定义如下的 UI 结构&#xff1a; <template><view class"my-userinfo-container"><!-- 头像昵称区域 --><view class"top-box"><image src"…

蓝桥杯刷题冲刺 | 倒计时18天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录0.知识点1.乳草的入侵今天写 搜索题 0.知识点 DFS 设计步骤 确定该题目的状态&#xff08;包括边…