LeetCode 热题 100之链表1

1.相交链表

在这里插入图片描述
思路分析(直接上双指针):

  • 初始化两个指针,分别指向两个链表的头节点 headA 和 headB
  • 遍历两个链表,当指针到达链表的末尾时,将指针移动到另一个链表的头部
    • 如果链表相交,两个指针会在相交节点相遇
    • 如果没有相交,两个指针会在遍历完整个链表后都变成 None,最终返回 None。

具体实现代码(详解版):

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
       if(!headA || !headB) return nullptr;//任意链表为空

       ListNode *pA = headA;
       ListNode *pB = headB;

       //当指针相等时,表示找到了相交节点,或者两个指针都为nullptr
       while(pA != pB){
        //当指针到达末尾时,重定向到另一个链表的头部
         pA = pA ? pA->next : headB;//不为空则指向下一个节点,为空指向另一个链表头
         pB = pB ? pB->next : headA;
       }

       return pA;// 返回相交节点或 nullptr

        
    }
};

2.反转链表

在这里插入图片描述
思路分析1(迭代法):通过迭代的方法,我们可以使用三个指针来反转链表。

  • 初始化三个指针:
    • prev指向当前节点的前一个节点,初始化为nullptr;
    • current指向当前节点,初始为头节点head;
    • next用于保存当前节点的下一个节点,防止丢失。
  • 遍历链表:
    • 每一步中,保存当前节点的下一个节点;
    • 将当前节点的next指针指向前一个节点
    • 移动指针,继续反转

具体实现代码(详解版):

/**
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr; // 前一个节点
        ListNode* current = head;  // 当前节点

        while (current) {
            ListNode* next = current->next; // 保存下一个节点
            current->next = prev;            // 反转当前节点的指针
            prev = current;                  // 移动 prev 到当前节点
            current = next;                  // 移动到下一个节点
        }

        return prev; // prev 成为新的头节点
    }
};

思路分析2(递归无敌法):

  • 递归基本情况:如果head为空或只有一个节点,直接返回head
  • 递归步骤:反转后面的链表并将当前节点的 next 指针指向 head,同时将当前节点的 next 设置为 nullptr。

具体实现代码(详解版):

/**
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //链表为空或者只有一个元素
        if(!head || !head -> next) return head;
        
        //递归反转链表
        ListNode* newHead = reverseList(head->next);

        //反转当前指针
        head->next->next = head;
        head->next = nullptr;

        return newHead;//返回新的头节点
    }
};

3.回文链表

在这里插入图片描述
思路分析1(赋值+头尾比较)

  • 遍历链表,将每个节点的值存储到vals中;
  • 比较元素
    • 使用两个指针i和j,分别指向vals数组的开始和结束,在for循环中,依次比较vals[i]和vals[j]的值
    • 如果发现任何不相等的元素,立即返回false,说明链表不是回文;
    • 如果所有元素都匹配,返回true,说明链表是回文。

具体实现代码(详解版):

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<int> vals; // 用于存储链表中的节点值
        
        // 1. 遍历链表并将节点值存储到数组中
        while (head != nullptr) {
            vals.emplace_back(head->val); // 将当前节点值加入数组
            head = head->next; // 移动到下一个节点
        }

        // 2. 比较数组的前半部分和后半部分
        for (int i = 0, j = (int)vals.size() - 1; i < j; ++i, --j) {
            if (vals[i] != vals[j]) {
                return false; // 如果不相等,则不是回文
            }
        }
        return true; // 所有值都匹配,则是回文链表
    }
};

思路分析2(使用栈):利用栈的特性来存储链表的前半部分,然后在遍历后半部分时与栈中的值进行比较

具体实现代码(详解版):

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (!head || !head->next) {
            return true; // 空链表或只有一个节点是回文
        }

        std::stack<int> s;
        ListNode* current = head;

        // 1. 将前半部分的节点值压入栈中
        while (current) {
            s.push(current->val);
            current = current->next;
        }

        // 2. 比较栈中的值与链表中的值
        current = head;
        while (current) {
            if (s.top() != current->val) {
                return false;
            }
            s.pop();
            current = current->next;
        }

        return true; // 如果所有值都匹配,则是回文链表
    }
};

以上两种方法的时间复杂度和空间复杂度都是 O ( n ) . O(n). O(n).下面利用快慢指针法,以空间复杂度 O ( 1 ) O(1) O(1)实现回文链表的判断。

思路分析3(快慢指针):

  • 使用快慢指针找到链表的中间节点:快指针 fast 每次移动两个节点,慢指针 slow 每次移动一个节点。当快指针到达链表末尾时,慢指针位于链表的中间位置
  • 反转链表的后半部分:从中间节点开始,反转后半部分的链表,使其变为从尾部到中间的逆序链表。
  • 比较前半部分和反转后的后半部分:用两个指针从头部和反转后的中间开始向后比较,若有不相等的值则不是回文链表。

具体实现代码(详解版):


class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(!head || !head->next) return true;

        //1.使用快慢指针找到中间节点
        ListNode *slow = head,*fast = head;
        while(fast && fast->next){
            slow = slow->next;
            fast = fast->next->next;
        }

        //2.反转后半部分链表
        ListNode *prev = nullptr;
        while(slow){
            ListNode *nextNode = slow->next;
            slow->next = prev;
            prev = slow;
            slow = nextNode;
        }
        //比较前半部分和反转后的后半部分
        ListNode *left = head;
        ListNode *right = prev;//prev现在是反转后的链表头
        while(right){//只需比较后半部分的节点数
            if(left->val != right->val) return false;

            left = left->next;
            right = right->next;

        }

        return true;//如果没有发现不相等的节点,则回文链表
    }
};

4.环形列表

在这里插入图片描述
思路分析1(哈希表):我们可以使用哈希表来存储所有已经访问过的节点。每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表即可。

具体实现代码(详解版):

class Solution {
public:
    bool hasCycle(ListNode *head) {
        unordered_set<ListNode*> visited;

        while (head != nullptr) {
            // 检查当前节点是否已访问过
            if (visited.count(head)) {
                return true; // 存在环
            }
            visited.insert(head); // 将当前节点标记为已访问
            head = head->next;
        }

        return false; // 没有环
    }
};

思路分析2(快慢指针):

  • 快慢指针:slow 每次前进一步,而 fast 每次前进两步。如果 fast 和 slow 在某一时刻相遇,说明链表有环。
  • 退出条件:如果 fast 或 fast->next 为 nullptr,则链表没有环。
  • 这样实现的时间复杂度为 O(n),空间复杂度为 O(1),是判断链表是否有环的标准解法。
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (!head || !head->next) return false;

        ListNode *slow = head;
        ListNode *fast = head->next;

        while (fast != slow) {
            if (!fast || !fast->next) return false;
            slow = slow->next;
            fast = fast->next->next;
        }

        return true;  // fast和slow相遇表示有环
    }
};

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

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

相关文章

【含开题报告+文档+PPT+源码】基于SSM的旅游与自然保护平台开发与实现

开题报告 围场县拥有丰富的自然景观和野生动植物资源&#xff0c;同时面临着旅游业发展和自然保护之间的平衡问题&#xff0c;通过强调自然保护&#xff0c;这个平台可以教育游客如何尊重和保护当地的生态环境。同时&#xff0c;平台还可以提供关于生态保护的信息&#xff0c;…

立仪光谱共焦在玻璃上奥秘与应用

在现代工业和科学研究中&#xff0c;玻璃因其透明、坚硬和易加工的特性被广泛应用于各个领域。然而&#xff0c;玻璃的厚度测量一直是困扰业界的一大难题。传统的千分尺或电容式传感器虽然在一定程度上能满足生产需求&#xff0c;但在精度、效率以及适用范围上存在明显的局限。…

中航资本:市盈率静和动分别是什么意思?市盈率静和动看哪个准?

市盈率静和动别离是什么意思&#xff1f; 市盈率静就是指静态市盈率&#xff0c;是以最新一期的年报为核算根据&#xff0c;其数据核算公式为&#xff1a;总市值最新一期的年报的净利润&#xff0c;年报的净利润可所以作用快报或作用预告发布的数据。 市盈率动就是动态市盈率…

动态规划 - 背包问题 - 完全背包

完全背包物品数量无限制&#xff0c;可以使用多次的实现方式&#xff1a;背包正序遍历 0-1背包&#xff1a;先物品后背包&#xff0c;物品正序、背包倒序&#xff08;保证每个物品只用一次&#xff09; 完全背包&#xff1a;先后顺序都可以&#xff0c;物品正序、背包正序 如果…

基于卷积神经网络的苹果病害识别与防治系统,resnet50,mobilenet模型【pytorch框架+python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 苹果病害识别与防治系统&#xff0c;卷积神经网络&#xff0c;resnet50&#xff0c;mobilenet【pytorch框架&#xff0c;python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷积…

appium+mumu模拟器 嚼碎菜鸟教程

1、android sdk 下载安装 下载地址&#xff1a;https://www.androiddevtools.cn/index.html# 选择版本&#xff1a;android sdk【sdk tools:installer_r24.4.1-windows.exe】 参考步骤&#xff1a;https://blog.csdn.net/2401_83004375/article/details/139300339 2、jdk 安装…

day11:磁盘管理

一&#xff0c;磁盘概述 磁盘概述 磁盘是一种持久性存储设备&#xff0c;用于存储操作系统、应用程序和数据。磁盘通常分为**机械硬盘&#xff08;HDD&#xff09;和固态硬盘&#xff08;SSD&#xff09;**两种&#xff0c;HDD 基于旋转的磁性盘片&#xff0c;而 SSD 基于闪存…

【WRF数据处理】基于GIS4WRF插件将geotiff数据转为tiff(geogrid,WPS所需数据)

【WRF数据处理】基于GIS4WRF插件将geotiff数据转为tiff&#xff08;geogrid&#xff0c;WPS所需数据&#xff09; 数据准备&#xff1a;以叶面积指数LAI为例QGis实操&#xff1a;基于GIS4WRF插件将geotiff数据转为tiff警告&#xff1a;GIS4WRF: Input layer had an unexpected …

ES8JC-ASEMI超快恢复二极管ES8JC

编辑&#xff1a;ll ES8JC-ASEMI超快恢复二极管ES8JC 型号&#xff1a;ES8JC 品牌&#xff1a;ASEMI 封装&#xff1a;SMC 安装方式&#xff1a;贴片 批号&#xff1a;最新 恢复时间&#xff1a;35ns 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;8A 最大循…

ECCV 2024论文分享┆Agent Attention: Softmax注意力和线性注意力的高效融合

简介 本推文主要介绍了由清华大学黄高老师团队发表在ECCV 2024上的一篇论文《Agent Attention: On the Integration of Softmax and Linear Attention》&#xff0c;文中提出了一种新型的代理注意力&#xff08;Agent Attention&#xff09;。近年来&#xff0c;Transformer在…

Github 2024-10-29Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-10-29统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10TypeScript项目1gpt4free存储库:强大语言模型的集合 创建周期:300 天开发语言:Python协议类型:GNU General Public License v3…

【Java】逻辑控制 —— 三大结构 和 猜数字游戏

目录 1. 顺序结构 2. 分支结构【与C略有不同】 2.1 if语句 2.2 switch语句 注意事项【与C不同】 3. 循环结构【与C略有不同】 3.1 while循环 * break和continue 3.2 for循环 3.3 do while循环 * 输入的判断&#xff08;hasNext&#xff09; 4. 猜数字游戏 1. 顺序结…

大文件秒传,分片上传,断点续传

大文件分片上传 一 功能描述 1.文件通过web端分片多线程上传到服务端&#xff0c;然后web端发起分片合并&#xff0c;完成大文件分片上传功能 2.上传过的大文件&#xff0c;实现秒传 3.上传过程中&#xff0c;服务异常退出&#xff0c;实现断点续传 二 流程图 三 代码运行…

【含开题报告+文档+PPT+源码】基于Java的社会公益平台

开题报告 随着社会的不断进步和人们公益意识的日益增强&#xff0c;社会公益事业在全球范围内得到了广泛的关注和参与。然而&#xff0c;传统的公益模式往往受到信息不对称、资源分散、管理效率低下等问题的困扰&#xff0c;导致公益活动的效果有限&#xff0c;难以满足社会的…

【C语言】C语言入门--函数

文章目录 前言一、函数的概念一、pandas是什么&#xff1f;二、库函数 1.标准库和头文件2.库函数的使用方法3.库函数文档的一般格式三、自定义函数四、形参和实参五、return语句六、数组做函数参数七、嵌套调用和链式访问 1.嵌套调用2.链式访问八、函数的声明和定义 1.单个文件…

C++在实际项目中的应用第二节:C++与区块链

第五章&#xff1a;C在实际项目中的应用 第二课&#xff1a;C与区块链 区块链技术因其去中心化、不可篡改和透明性而受到广泛关注。在这门课程中&#xff0c;我们将深入探讨区块链的基本原理、智能合约的开发以及实际应用的案例分析&#xff0c;重点使用 C 作为实现语言&…

微服务之网关、网关路由、网关登录校验

简介&#xff1a;来源&#xff1a;SpringCloud微服务开发与实战&#xff0c;java黑马商城项目微服务实战开发&#xff08;涵盖MybatisPlus、Docker、MQ、ES、Redis高级等&#xff09; 认识网关 前端请求不能直接访问微服务&#xff0c;而是要请求网关&#xff1a; 网关可以做…

服务环境的搭建

一、基础环境搭建 1、python3 准备相关的jar包 Index of /ftp/python/3.7.9/ scp Python-3.7.9.tgz root192.168.1.245:/opt/dockerinstall/python3/ yum -y install gcc yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel…

【语音转文本新体验】Windows部署Whisper Web结合内网穿透轻松远程转录——“cpolar内网穿透”

文章目录 前言1.本地部署Whisper Web1.1 安装git1.2 安装Node.js1.3 运行项目 2. Whisper Web使用介绍3. 安装Cpolar内网穿透4. 配置公网地址5. 公网访问测试6. 配置固定公网地址 前言 OpenAI开源的 Whisper 语音转文本模型效果都说还不错&#xff0c;今天就给大家推荐 GitHub…

[A-14]ARMv8/ARMv9-Memory-内存模型的类型(Device Normal)

ver0.1 [看前序文章有惊喜。] 前言 前面花了很大的精力把ARM构建的VMSA中的几个核心的议题给大家做了介绍,相信大家已经能够理解并掌握ARM的内存子系统的工作原理大致框架。接下来我们会规划一些文章,对ARM内存子系统的一些细节做一下介绍,使ARM的内存子系统更加的丰满。本…