【LeetCode_206】反转链表

【LeetCode_206】反转链表

刷爆LeetCode系列

LeetCode第206题:反转链表

github地址

有梦想的电信狗

前言

本文用C++实现LeetCode206题:反转链表


题目描述

在这里插入图片描述
在这里插入图片描述

题目与思路分析

目标分析

  1. 有单链表的头节点 head ,反转原链表
  2. 返回反转后的链表的头指针
  3. 提高要求:时间复杂度为O(n),空间复杂度为O(1)

思路一:反转链表的指针指向

思路:遍历一遍链表,将当前结点的next指针,指向其前驱节点,即可实现链表的反转。最终返回链表的最后一个节点即可(原链表的最后一个结点作为新链表的头结点

操作

  • head == nullptr时,为空链表,直接return nullptr;
  • 遍历链表
    • curNode:从头结点head开始,依次遍历链表,更改指针的指向
      • 当前结点的next指针,指向其前驱节点,因此需要提前保存当前结点的前驱节点
    • curPrev:记录curNode的前驱节点,方便反转指针指向,初始值为nullptr
    • curNext:提前保存curNode的后继结点,防止反转指针指向curNode无法移动到下一个结点
  • 更改指向
    • 保存curNode的下一个结点ListNode* curNext = curNode->next
    • 更改当前结点的next指针curNode->next = curPrev
    • curPrev和curNode依次向后移动
      • curPrev = curNode;
      • curNode = curNext;
  • 最终return curPrevcurPrev最后的位置就是链表的尾结点
在 while 循环内保存 curNext,保证了 curNode 一定不为空,避免了对空指针解引用可以保证一定可以取到 curNext,为空或非空
在这里插入图片描述
  • 链表只有一个结点的情况
在这里插入图片描述

思路二:取链表的结点,头插到新链表中

思路:创建一个新链表,头结点为newHead,初始为nullptr。遍历原链表,将原链表中的节点依次头插到新链表中,头插后更新newHead,即可实现链表的反转,最终返回newHead

操作

  • 遍历链表
    • curNode:从头结点head开始,依次遍历链表,进行头插操作。将当前结点的next指针,指向新链表的newHead,再更新newHead的值。之后curNode移向下一个结点。由于头插后curNode->next的值更改,不能通过curNode = curNode->next的方式移动,因此需要提前保存curNode的后继节点
    • curNext:提前保存curNode的后继结点,防止头插curNode无法移动到下一个结点
  • 头插
    • 保存curNode的下一个结点ListNode* curNext = curNode->next
    • 更改当前结点的next指针curNode->next = newHead
    • 更新newHead的值newHead = curNode;
    • curNode向后移动curNode = curNext;
  • 最终return newHeadnewHead即为新链表的头结点
在 while 循环内保存 curNext,保证了 curNode 一定不为空,避免了对空指针解引用可以保证一定可以取到 curNext,为空或非空
在这里插入图片描述

代码实现

思路一:反转指针指向

以下两种写法是保存curNext指针的方式不同

  • 在while循环外保存curNext指针,初始值可能为nullptr
classSolution{public: ListNode*reverseList(ListNode* head){// 空链表的情况if(head ==nullptr)returnnullptr; ListNode* curNode = head; ListNode* curPrev =nullptr; ListNode* curNext = head->next;// 链表只有一个结点的情况if(curNext ==NULL)return head;while(curNode){ curNode->next = curPrev; curPrev = curNode; curNode = curNext;// curNext可能为空,需要判断 非空时再向后移动if(curNext) curNext = curNext->next;}return curPrev;}};
  • 在while循环外保存curNext指针:不涉及对curNext的解引用,即使为空也不影响
// 思路一、反转指针classSolution{public: ListNode*reverseList(ListNode* head){if(head ==nullptr)returnnullptr; ListNode* curNode = head; ListNode* curPrev =nullptr;while(curNode){// 在 while 循环内保存 curNext,保证了 curNode 一定不为空,避免了对空指针解引用// 可以保证一定可以取到 curNext ,为空或非空 ListNode* curNext = curNode->next; curNode->next = curPrev; curPrev = curNode; curNode = curNext;}return curPrev;}};

思路二:取原链表中的节点,头插到新链表

  • 取链表中的节点,头插到新链表
// 思路二、取链表中的节点,头插到新链表classSolution{public: ListNode*reverseList(ListNode* head){ ListNode* newHead =nullptr,*curNode = head;while(curNode){// 提前保存 curNode 的下一个结点 ListNode* curNext = curNode->next;// 头插 curNode->next = newHead; newHead = curNode;// curNode 向后移动 curNode = curNext;}return newHead;}};

试错代码

  • 初次尝试时的错误代码:
  • 错误原因:
    • 第一次头插后,链表直接断开了,curNode无法移动到下一个结点
// 思路二 取结点,头插到新链表中classSolution{public: ListNode*reverseList(ListNode* head){ ListNode* newHead =nullptr; ListNode* curNode = head;while(curNode){// 错误原因,第一次头插后,链表直接断开了,curNode无法移动到下一个结点if(newHead ==nullptr){ newHead = curNode; newHead->next =nullptr;}else{ curNode->next = newHead; newHead = curNode;} curNode = curNode->next;}return newHead;}};
  • 纠错后的代码
// 思路二 取结点,头插到新链表中classSolution{public: ListNode*reverseList(ListNode* head){ ListNode* newHead =nullptr; ListNode* curNode = head;while(curNode){ ListNode* curNext = curNode->next;// 提前保存 下一个结点if(newHead ==nullptr){ newHead = curNode; newHead->next =nullptr;}else{ curNode->next = newHead; newHead = curNode;} curNode = curNext;}return newHead;}};

算法代码优化

思路一优化:

  • 优化点:无需单独判断链表为空时的情况
    • 链表为空时不进入while循环,直接返回 curPrev,而 curPrev 初始值为 nullptr
// 思路一、反转指针classSolution{public: ListNode*reverseList(ListNode* head){ ListNode* curNode = head,*curPrev =nullptr;while(curNode){// 在 while 循环内保存 curNext,保证了 curNode 一定不为空,避免了对空指针解引用// 可以保证一定可以取到 curNext ,为空或非空 ListNode* curNext = curNode->next; curNode->next = curPrev; curPrev = curNode; curNode = curNext;}return curPrev;}};
  • 思路二已经足够简洁正确,无需优化

以上就是本文的所有内容了,如果觉得文章对你有帮助,欢迎 点赞⭐收藏 支持!如有疑问或建议,请在评论区留言交流,我们一起进步

分享到此结束啦
一键三连,好运连连!
你的每一次互动,都是对作者最大的鼓励!征程尚未结束,让我们在广阔的世界里继续前行! 🚀

Read more

在 VSCode 中本地运行 DeepSeek,打造强大的私人 AI

在 VSCode 中本地运行 DeepSeek,打造强大的私人 AI

本文将分步向您展示如何在本地安装和运行 DeepSeek、使用 CodeGPT 对其进行配置以及开始利用 AI 来增强您的软件开发工作流程,所有这些都无需依赖基于云的服务。  步骤 1:在 VSCode 中安装 Ollama 和 CodeGPT         要在本地运行 DeepSeek,我们首先需要安装Ollama,它允许我们在我们的机器上运行 LLM,以及CodeGPT,它是集成这些模型以提供编码辅助的 VSCode 扩展。 安装 Ollama Ollama 是一个轻量级平台,可以轻松运行本地 LLM。 下载Ollama 访问官方网站:https://ollama.com * 下载适合您的操作系统(Windows、macOS 或 Linux)的安装程序。 * 验证安装 安装后,打开终端并运行: ollama --version  如果 Ollama 安装正确,

By Ne0inhk
DeepSeek-R1是真码农福音?我们问了100位开发者……

DeepSeek-R1是真码农福音?我们问了100位开发者……

从GitHub Copilot到DeepSeek-R1,AI编程工具正在引发一场"效率革命",开发者们对这些工具的期待与质疑并存。据Gartner预测,到2028年,将有75%的企业软件工程师使用AI代码助手。 眼看着今年国产选手DeepSeek-R1凭借“深度思考”能力杀入战场,它究竟是真码农福音还是需要打补丁的"潜力股"? ZEEKLOG问卷调研了社区内来自全栈开发、算法工程师、数据工程师、前端、后端等多个技术方向的100位开发者(截止到2月25日),聚焦DeepSeek-R1的代码生成效果、编写效率、语法支持、IDE集成、复杂代码处理等多个维度,一探DeepSeek-R1的开发提效能力。 代码生成效果:有成效但仍需提升 * 代码匹配比例差强人意 在代码生成与实际需求的匹配方面,大部分开发者(58人)遇到生成代码与实际需求完全匹配无需修改的比例在40%-70%区间,12人遇到代码匹配比例在70%-100%这样较高的区间。 然而,有30人代码匹配比例低于40%。这说明DeepSeek-R1在代码生成方面有一定效果,但在部分复杂或特定场景下,仍有很大的提升空间。

By Ne0inhk
AI+游戏开发:如何用 DeepSeek 打造高性能贪吃蛇游戏

AI+游戏开发:如何用 DeepSeek 打造高性能贪吃蛇游戏

文章目录 * 一、技术选型与准备 * 1.1 传统开发 vs AI生成 * 1.2 环境搭建与工具选择 * 1.3 DeepSeek API 初步体验 * 二、贪吃蛇游戏基础实现 * 2.1 游戏结构设计 * 2.2 初始化游戏 * 2.3 DeepSeek 生成核心逻辑 * 三、游戏功能扩展 * 3.1 多人联机模式 * 3.2 游戏难度动态调整 * 3.3 游戏本地保存与回放 * 3.4 跨平台移植 * 《Vue.js项目开发全程实录/软件项目开发全程实录》 * 编辑推荐 * 内容简介 * 作者简介 * 目录 一、

By Ne0inhk
[DeepSeek] 入门详细指南(上)

[DeepSeek] 入门详细指南(上)

前言 今天的是 zty 写DeepSeek的第1篇文章,这个系列我也不知道能更多久,大约是一周一更吧,然后跟C++的知识详解换着更。 来冲个100赞兄弟们 最近啊,浙江出现了一匹AI界的黑马——DeepSeek。这个名字可能对很多人来说还比较陌生,但它已经在全球范围内引发了巨大的关注,甚至让一些科技巨头感到了压力。简单来说这 DeepSeek足以改变世界格局                                                   先   赞   后   看    养   成   习   惯  众所周知,一篇文章需要一个头图                                                   先   赞   后   看    养   成   习   惯   上面那行字怎么读呢,让大家来跟我一起读一遍吧,先~赞~后~看~养~成~习~惯~ 想要 DeepSeek从入门到精通.pdf 文件的加这个企鹅群:953793685(

By Ne0inhk