Leetcode 108 交换链表中的节点

 1 题目

1721. 交换链表中的节点

给你链表的头节点 head 和一个整数 k 。

交换 链表正数第 k 个节点和倒数第 k 个节点的值后,返回链表的头节点(链表 从 1 开始索引)。

示例 1:

输入:head = [1,2,3,4,5], k = 2 输出:[1,4,3,2,5]

示例 2:

输入:head = [7,9,6,6,7,8,3,0,9,5], k = 5 输出:[7,9,6,6,8,7,3,0,9,5]

示例 3:

输入:head = [1], k = 1 输出:[1]

示例 4:

输入:head = [1,2], k = 1 输出:[2,1]

示例 5:

输入:head = [1,2,3], k = 2 输出:[1,2,3]

提示:

  • 链表中节点的数目是 n
  • 1 <= k <= n <= 105
  • 0 <= Node.val <= 100

2 代码实现

c++

/** * 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* swapNodes(ListNode* head, int k) { ListNode* first = head ; for (int i = 1 ; i < k ; ++ i){ first = first -> next ; } ListNode* second = head ; ListNode* fast = first ; while (fast -> next != nullptr){ fast = fast -> next ; second = second -> next ; } swap(second-> val , first->val); return head ; } }; 

js

/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } */ /** * @param {ListNode} head * @param {number} k * @return {ListNode} */ var swapNodes = function(head, k) { let first = head ; for (let i = 1 ; i < k ;++i){ first = first.next; } let second = head ; let fast = first ; while(fast.next){ fast = fast.next ; second=second.next; } const temp = first.val ; first.val = second.val ; second.val = temp ; return head ; };

注意js里面没有内置的swap函数!!!自己实现一下值的交换!!

思考

真的很直接的思路了,但是链表结点的操作顺序要小心,然后正数、 倒数实在是太直白了,正数不用说,倒数就是一个间隔k的前后指针就ok了。自己理一理思路试着写一下,思路很简单,难的地方是操作顺序和各种循环细节。要防止链表结点丢失。

题解

解题思路(贴合你的思考)

  1. 定位正数第 k 个节点:从头节点出发,移动 k-1 步,直接找到目标节点,这一步逻辑直白,只需注意循环次数。
  2. 定位倒数第 k 个节点:用 “前后指针(快慢指针)” 实现 —— 先让快指针走 k 步,再让快慢指针同步走,快指针到末尾时,慢指针就是倒数第 k 个节点,核心是利用 “间隔 k” 的特性,避免先遍历统计长度的二次遍历。
  3. 交换值而非节点:仅交换两个节点的 val,不修改链表的 next 指针,彻底避免节点丢失的问题,这是最简洁且安全的操作方式。

C++ 核心代码

/** * 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* swapNodes(ListNode* head, int k) { // 1. 找到正数第k个节点(注意从1开始索引) ListNode* first = head; for (int i = 0; i < k - 1; ++i) { first = first->next; // 移动k-1步,定位正数第k个节点 } // 2. 找到倒数第k个节点(前后指针法,避免节点丢失) ListNode* second = head; ListNode* fast = first; // 快指针先站在正数第k个节点,形成k步间隔 while (fast->next != nullptr) { // 快指针走到末尾时,慢指针就是倒数第k个 fast = fast->next; second = second->next; } // 3. 仅交换两个节点的值,无需修改链表结构,避免节点丢失 swap(first->val, second->val); // 返回原链表头节点 return head; } }; 

代码关键解释(贴合你的思考重点)

  1. 正数第 k 个节点定位
    • 循环 k-1 次而非 k 次,因为链表从 1 开始索引,初始的 first = head 已经是第 1 个节点,移动 k-1 步正好到第 k 个,这是容易出错的细节,需注意循环次数。
  2. 倒数第 k 个节点定位
    • 快指针 fast 直接从正数第 k 个节点起步,和慢指针 second(初始在头节点)形成 k 步的间隔,之后同步移动,直到快指针到链表末尾(fast->next == nullptr),此时慢指针恰好指向倒数第 k 个节点。
    • 这种方式只需一次遍历,且全程只操作指针移动,不会出现节点丢失的问题,符合你 “小心操作顺序、防止链表结点丢失” 的思考。
  3. 交换逻辑
    • 直接用 C++ 内置的 swap 函数交换两个节点的 val,无需修改 next 指针,是最安全的方式,彻底规避了链表节点操作中 “断链、丢节点” 的风险。

测试验证(力扣提交场景)

输入k输出
[1,2,3,4,5]2[1,4,3,2,5]
[7,9,6,6,7,8,3,0,9,5]5[7,9,6,6,8,7,3,0,9,5]
[1]1[1]
[1,2]1[2,1]

总结

  1. 核心逻辑:先精准定位两个目标节点,仅交换值而非节点,避免链表结构修改带来的节点丢失问题。
  2. 关键技巧:用间隔 k 的快慢指针一次遍历找到倒数第 k 个节点,时间复杂度 O (n),空间复杂度 O (1),符合高效要求。
  3. 细节注意:循环次数为 k-1 而非 k,快慢指针同步移动的终止条件是 fast->next == nullptr,这些细节保证了定位的准确性。

诶,原来直接交换这两个节点的val是可以的吗!?

自己乱写

/** * 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* swapNodes(ListNode* head, int k) { ListNode* first = head ; for (int i = 1 ; i < k ; ++ i){ first = first -> next ; } ListNode* second = head ; ListNode* fast = head ; while (fast -> next != nullptr){ fast = fast -> next ; second = second -> next ; } swap(second-> val , first->val); return head ; } }; 

解答错误!!!!

啊,我发现了,fast要先站在first的地方,形成k个间隔啊!

3 小结

自己多写写,多练,注意js里面的api,熟悉起来js的语法!!!

踩坑

易错点错误写法正确写法原因
fast 初始位置fast = headfast = first必须形成 k 步间隔,才能定位倒数第 k 个节点

循环次数

(找正数第 k 个节点)

i <= ki = 0 开始i = 1 开始,i < k(或 i = 0 开始,i < k-1链表从 1 索引,初始 first=head 是第 1 个节点,只需移动 k-1 步
JS 交换值swap(a, b)临时变量 temp = a; a = b; b = tempJS 无内置 swap 函数,且基本类型是值传递

Read more

你以为你在部署 AI 助手,其实也可能在打开一扇“数据侧门”:OpenClaw 安全风险全解析

你以为你在部署 AI 助手,其实也可能在打开一扇“数据侧门”:OpenClaw 安全风险全解析

🔥 个人主页:杨利杰YJlio❄️ 个人专栏:《Sysinternals实战教程》《Windows PowerShell 实战》《WINDOWS教程》《IOS教程》《微信助手》《锤子助手》《Python》《Kali Linux》《那些年未解决的Windows疑难杂症》🌟 让复杂的事情更简单,让重复的工作自动化 你以为你在部署 AI 助手,其实也可能在打开一扇“数据侧门”:OpenClaw 安全风险全解析 * * 1、你以为你在装 AI 助手,其实你可能在给系统加一个“高权限自动化入口” * 2、OpenClaw 和普通 AI 最大的区别,到底在哪里? * 3、我为什么说:OpenClaw 更像“拿到部分权限的数字操作员”? * 4、为什么说 AI 助手不是“更聪明的搜索框”? * 5、OpenClaw 的 5

By Ne0inhk
OpenClaw 搭建全流程实战:从 0 部署到可控 AI Agent(附避坑与安全建议)

OpenClaw 搭建全流程实战:从 0 部署到可控 AI Agent(附避坑与安全建议)

近几个月,「AI Agent」成为技术圈的高频词,但大多数人停留在 Demo、插件和概念层。 真正能跑在本地 / 服务器、拥有真实权限、能持续执行任务的 Agent 并不多。 OpenClaw,正是目前少数几个工程完整、可部署、可二次开发的开源 AI Agent 框架之一。 这篇文章不讲愿景、不画饼,只讲怎么搭、怎么跑、怎么不翻车。 一、OpenClaw 到底是什么?先说清楚定位 一句话说明白: OpenClaw 是一个可部署在本地或服务器上的开源 AI Agent 框架,具备 Gateway(通信)、Dashboard(控制台)和 Skills(能力插件)三大核心模块。 和 ChatGPT / 插件的本质区别在于: 对比项普通 AI 工具OpenClaw运行位置云端本地

By Ne0inhk
猫头虎AI分享:无需OCR,基于ColQwen2、Qwen2.5和Weaviate对PDF进行多模态RAG的解决方案

猫头虎AI分享:无需OCR,基于ColQwen2、Qwen2.5和Weaviate对PDF进行多模态RAG的解决方案

无需OCR,基于ColQwen2、Qwen2.5和Weaviate对PDF进行多模态RAG的解决方案 关键词:多模态RAG、ColQwen2、Qwen2.5-VL、Weaviate 向量数据库、PDF 检索问答、无需 OCR、ColBERT 多向量、跨模态检索、MaxSim 相似度、知识库构建、AI 文档处理、视觉语言模型、晚交互(Late Interaction)、向量索引、Python 教程、HuggingFace、Colab、MPS、GPU 本文面向初学者,手把手搭建一个“无需 OCR 与分块”的 PDF 多模态 RAG 流水线:把 PDF 页面截图直接送入 ColQwen2 生成多向量(multi-vector)

By Ne0inhk
人工智能:深度学习中的卷积神经网络(CNN)实战应用

人工智能:深度学习中的卷积神经网络(CNN)实战应用

人工智能:深度学习中的卷积神经网络(CNN)实战应用 1.1 本章学习目标与重点 💡 学习目标:掌握卷积神经网络的核心原理、经典网络架构,以及在图像分类任务中的实战开发流程。 💡 学习重点:理解卷积层、池化层的工作机制,学会使用 TensorFlow 搭建 CNN 模型并完成训练与评估。 1.2 卷积神经网络核心原理 1.2.1 卷积层:提取图像局部特征 💡 卷积层是 CNN 的核心组件,其作用是通过卷积核对输入图像进行局部特征提取。 卷积核本质是一个小型的权重矩阵。它会按照设定的步长在图像上滑动。每滑动一次,卷积核就会与对应区域的像素值做内积运算,输出一个特征值。 这个过程可以捕捉图像的边缘、纹理等基础特征。 ⚠️ 注意:卷积核的数量决定了输出特征图的通道数,数量越多,提取的特征维度越丰富。 ① 定义一个 3×3 大小的卷积核,步长设为 1,填充方式为 SAME

By Ne0inhk