力扣234.回文链表

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。



示例 1:



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

示例 2:



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



提示:链表中节点数目在范围[1, 105] 内0 <= Node.val <= 9

题目解读

回文链表:本质是单链表的一种特殊结构 —— 从链表头部到尾部遍历得到的节点值序列,和从尾部到头部遍历得到的序列完全一致,比如 "abba"、"12321",正读和反读都相同。我们往往使用这“对称性”解决问题。

思路一

将链表转换为数组后使用双指针判断是否是回文。

具体步骤与解析

1.统计链表长度

 int len = 0;//用以储存链表长度 ListNode cur = head;//从头节点出发 while (cur != null) { len++; // 每遍历一个节点,长度+1 cur = cur.next; // 游标后移 } 

作用:确定后续数组的长度,避免数组越界或浪费空间。

2.将链表值存入数组

 cur = head; // 重置游标,回到链表头 int[] res = new int[len]; // 根据长度创建数组 for (int i = 0; i < res.length; i++) { res[i] = cur.val; // 存入当前节点值 cur = cur.next; // 游标后移 }

注意:这里 for 循环的终止条件是 i < res.length,和链表长度完全匹配,不会遗漏或越界。

3.双指针判断回文

 for (int i = 0, j = len - 1; i < j; i++, j--) { if (res[i] != res[j]) { // 对称位置值不等,直接返回false return false; } } return true; // 所有对称位置相等,是回文 } }

左指针 i 从数组头部(i=0)开始,右指针 j 从数组尾部(j=len-1)开始,只要有一对值不相等,直接返回 false,反之若循环结束(i >= j)都未发现不相等,返回 true。

核心思路总结:先统计长度→再存值到数组→双指针判回文。

完整代码

class Solution { public boolean isPalindrome(ListNode head) { int len = 0; ListNode cur = head; while (cur != null) { len++; cur = cur.next; } cur = head; int[] res = new int[len]; for (int i = 0; i < res.length; i++){ res[i] = cur.val; cur = cur.next; } for (int i = 0, j = len - 1; i < j; i++, j--){ if (res[i] != res[j]){ return false; } } return true; } }

思路二

先使用快慢指针找到链表中点将链表分为两个部分,再将后部分链表反转与前部分一一对应来判断回文链表。

具体步骤与解析

1.处理边界情况

 if (head == null || head.next == null) return true;

空链表 或 只有 1 个节点的链表,本身就是回文,直接返回 true。

2.快慢指针找链表中点

 while (fast != null && fast.next != null) { pre = slow; // 记录slow的前一个节点(分割点) slow = slow.next; // 慢指针走1步 fast = fast.next.next;// 快指针走2步 }

慢指针(slow)每次走 1 步,快指针(fast)每次走 2 步,当 fast 走到链表末尾时,slow 恰好走到链表后半段的起点,pre 始终记录 slow 的前一个节点,用于后续分割链表。

3.分割链表 + 反转后半段

 pre.next = null; // 切断前半段和后半段的连接 // 前半段链表的头 ListNode cur1 = head; // 反转后半段链表,得到反转后的头 ListNode cur2 = reverseList(slow); 

辅助方法(reverseList)

 ListNode reverseList(ListNode head) { ListNode tmp = null; // 临时存储下一个节点 ListNode pre = null; // 记录当前节点的前一个节点 while (head != null) { tmp = head.next; // 先保存下一个节点,避免断链 head.next = pre; // 当前节点指向前一个节点(反转) pre = head; // pre后移到当前节点 head = tmp; // head后移到原本的下一个节点 } return pre; // 反转后的链表头 } }

4.对比前后两段链表

 while (cur1 != null) { if (cur1.val != cur2.val) { return false; } cur1 = cur1.next; cur2 = cur2.next; } return true; }

逐一比较两个链表的节点,值只要有一个值不相等,就不是回文;全部相等则是回文。

完整代码

 class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = null; } } class Solution { public boolean isPalindrome(ListNode head) { if (head == null || head.next == null) return true; ListNode slow = head; ListNode fast = head; ListNode pre = head; while (fast != null && fast.next != null) { pre = slow; slow = slow.next; fast = fast.next.next; } pre.next = null; ListNode cur1 = head; ListNode cur2 = reverseList(slow); while (cur1 != null) { if (cur1.val != cur2.val) { return false; } cur1 = cur1.next; cur2 = cur2.next; } return true; } ListNode reverseList(ListNode head) { ListNode tmp = null; ListNode pre = null; while (head != null) { tmp = head.next; head.next = pre; pre = head; head = tmp; } return pre; } }

Read more

❿⁄₁₄ ⟦ OSCP ⬖ 研记 ⟧ 密码攻击实践 ➱ 传递Net-NTLMv2哈希

❿⁄₁₄ ⟦ OSCP ⬖ 研记 ⟧ 密码攻击实践 ➱ 传递Net-NTLMv2哈希

郑重声明:本文所涉安全技术仅限用于合法研究与学习目的,严禁任何形式的非法利用。因不当使用所导致的一切法律与经济责任,本人概不负责。任何形式的转载均须明确标注原文出处,且不得用于商业目的。 🔋 点赞 | 能量注入 ❤️ 关注 | 信号锁定 🔔 收藏 | 数据归档 ⭐️ 评论 | 保持连接💬 🌌 立即前往 👉晖度丨安全视界🚀 ▶ 信息收集  ▶ 漏洞检测 ▶ 初始立足点  ▶ 权限提升 ▶ 横向移动 ➢ 密码攻击 ➢ 传递Net-NTLMv2哈希🔥🔥🔥 ▶ 报告/分析 ▶ 教训/修复 目录 1.密码破解 1.1 破解Windows哈希实践 1.1.4 传递Net-NTLMv2哈希概述 1.1.4.1 攻击背景 1.1.4.2 攻击流程 1.1.

By Ne0inhk
《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题

《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 01.第N个泰波拉契数 * 解法(动态规划): * 算法流程: * C++算法代码: * 算法总结&&笔记展示: * 02.三步问题 * 解法(动态规划): * 算法思路: * C++算法代码: * 算法总结&&笔记展示: * 结尾: 前言: 聚焦算法题实战,系统讲解三大核心板块:优选算法:剖析动态规划、二分法等高效策略,学会寻找“最优解”。 递归与回溯:掌握问题分解与状态回退,攻克组合、排列等难题。 贪心算法:理解“

By Ne0inhk
无中生有——无监督学习的原理、算法与结构发现

无中生有——无监督学习的原理、算法与结构发现

“世界上绝大多数数据都没有标签。 真正的智能,不是在已知答案中选择,而是在混沌中发现秩序。” ——无监督学习的哲学 一、为什么需要无监督学习? 在前七章中,我们系统学习了监督学习(Supervised Learning)的核心范式:给定输入 x\mathbf{x}x 和对应标签 yyy,学习映射 f:x↦yf: \mathbf{x} \mapsto yf:x↦y。无论是线性回归、决策树,还是神经网络,都依赖于标注数据这一稀缺资源。 然而,现实世界的数据绝大多数是未标注的: * 用户浏览日志(只有行为,没有“好/坏”标签); * 医学影像(只有图像,没有诊断结论); * 社交网络(只有连接关系,没有群体划分); * 传感器时序(只有数值流,没有异常标记)

By Ne0inhk
Java 面试篇-MySQL 专题(如何定位慢查询、如何分析 SQL 语句、索引底层数据结构、什么是聚簇索引?什么是非聚簇索引?知道什么是回表查询?什么是覆盖索引?事务的特性、并发事务带来的问题?)

Java 面试篇-MySQL 专题(如何定位慢查询、如何分析 SQL 语句、索引底层数据结构、什么是聚簇索引?什么是非聚簇索引?知道什么是回表查询?什么是覆盖索引?事务的特性、并发事务带来的问题?)

🔥博客主页: 【小扳_-ZEEKLOG博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 MySQL 中,如何定位慢查询?         2.0 发现了 SQL 语句执行很慢,如何分析呢?         3.0 什么是索引?         4.0 索引的底层数据结构了解过吗?         5.0 B 树与 B+ 树的区别是什么呢?         6.0 什么是聚簇索引?什么是非聚簇索引?         7.0 知道什么是回表查询吗?         8.0 知道什么是覆盖索引吗?         9.0 MySQL 超大分页怎么处理?         10.0 索引创建原则有哪些?         11.0 什么情况下索引失效?

By Ne0inhk