【题目】给定一个单链表的头节点head,请判断该链表是否为回文结构。
【例子】1->2->1, 返回true; 1->2- ->2->1,返回true; 15->6->15, 返回true;
1->2->3, 返回false。
【提高】如果链表长度为N,时间复杂度达到O(N),能否做到额外空间复杂度达到O(1)?

解答本题用到了快慢指针的技巧,所以先介绍一下快慢指针,它主要作用是找到链表的中间节点。

链表快慢指针介绍:

慢指针slow一次走1步,快指针F一次走2步,fast刚越界时S刚好走到中间位置,边界条件需具体情况来定制。

边界条件包括快慢指针的起始位置,和循环(遍历)的终止条件,由此来控制慢指针slow的最终落点。

通常边界条件的设置有如下几种情况:

    //为避免段错误,假设前面已有空指针的判断
//边界条件一:
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;
} //循环结束后,slow跑到mid处(奇数个node)或右半边第一个node处(偶数个node),fast跑到尾节点或null处//边界条件二:
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {slow = slow.next;fast = fast.next.next;
} //循环结束后,slow跑到mid处(奇数个node)或左半边最后一个node处(偶数个node),fast跑到尾节点或null处//边界条件三:
ListNode slow = head.next;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {slow = slow.next;fast = fast.next.next;
}  //循环结束后,slow跑到右半边第一个节点处(无论奇偶),fast跑到尾节点或倒数第二个节点处//边界条件四:
ListNode slow = head;
ListNode fast = head.next.next;
while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;
} //循环结束后,slow跑到mid前一个位置(偶数个node),或左半边倒数第二个node处(偶数个node),fast跑到尾节点或倒数第二个节点处

其中方法二、方法三都用到了快慢指针的技巧

方法一: 利用栈

 public static boolean isPalindrome1(ListNode head) {if (head == null || head.next == null) {return true;}Stack<Integer> stk = new Stack<>();ListNode cur = head;while (cur != null) {stk.push(cur.val);cur = cur.next;}cur = head;while (cur != null) {if ( cur.val != stk.pop()) {return false;}cur = cur.next;}return true;}

方法二:栈 + 快慢指针 (在方法一的基础上,空间利用减少一半)

    public static boolean isPalindrome2(ListNode head) {if (head == null || head.next == null) {return true;}//快慢指针 slow  fastListNode slow = head.next;ListNode fast = head;while (fast.next != null && fast.next.next != null) {fast = fast.next.next;   slow = slow.next;       }Stack<Integer> stk = new Stack<>();while (slow != null) {stk.push(slow.val);slow = slow.next;}ListNode cur = head;while(!stk.isEmpty()) {if (cur.val != stk.pop()) {return false;}cur = cur.next;}return true;}

方法三:快慢指针 + 反转链表   , 空间复杂度降为O(1)

//方法三: 反转链表的后半部分        时间复杂度O(N),空间复杂度O(1)public static boolean isPalindrome3(ListNode head) {//find mid node or left mid node by Mr.slow,  find tail-node by Mr.fastListNode n1 = head;  //慢指针ListNode n2 = head;  //快指针while (n2.next != null && n2.next.next != null) {n1 = n1.next;   //n1跑到mid处(奇数个node)或左半边最后一个node处(偶数个node)n2 = n2.next.next;}//反转后半部分的链表的指针指向n2 = n1.next;n1.next = null;ListNode n3 = null;while (n2 != null) {n3 = n2.next;      //记录n2的下一个节点n2.next = n1;      //反转n2的next指向n1 = n2;           //n1移动到下一个n2 = n3;           //n2移动到下一个}n2 = head;  //n2 -> headn3 = n1;    //记录尾节点//判断链表是否为回文boolean res = true;while (n1 != null && n2 != null) {if (n1.val != n2.val) {res = false;break;}n1 = n1.next;n2 = n2.next;}//将原链表后半部分调整回去n2 = n3.next;n3.next = null;while (n2 != null) {n1 = n2.next;       //记录n2的下一个节点n2.next = n3;       //反转n2的next指向n3 = n2;            //n3移动到下一个n2 = n1;            //n2移动到下一个}return res;}

测试:

  public static void main(String[] args) {ListNode L1 = new ListNode(1);PushBack(L1,2);PushBack(L1,3);PushBack(L1,4);printList(L1);System.out.println(isPalindrome3(L1));PushBack(L1,4);PushBack(L1,3);PushBack(L1,2);PushBack(L1,1);printList(L1);System.out.println(isPalindrome3(L1));}public static void PushBack(ListNode head, int val) {ListNode cur = head;ListNode newNode = new ListNode(val);while (cur.next != null) {cur = cur.next;}cur.next = newNode;}public static void printList(ListNode head) {if (head == null) {return;}ListNode cur = head;while (cur.next != null) {System.out.print(cur.val + " -> ");cur = cur.next;}System.out.println(cur.val);}//Definition for singly-linked list.
class ListNode {int val;ListNode next;ListNode() {val = 0;next = null;}ListNode(int val) {this.val = val;this.next = null;}ListNode(int val, ListNode next) {this.val = val;this.next = next;}}

结果如下:

1 -> 2 -> 3 -> 4
false
1 -> 2 -> 3 -> 4 -> 4 -> 3 -> 2 -> 1
true

算法练习:判断一个链表是否为回文结构相关推荐

  1. c语言数据结构判断回文数,C++数据结构与算法之判断一个链表是否为回文结构的方法...

    本文实例讲述了C++判断一个链表是否为回文结构的方法.分享给大家供大家参考,具体如下: 题目: 给定一个链表头节点head,请判断是否为回文结构 例如: 1->2->1 true 1-&g ...

  2. 数据结构与算法之打印两个有序链表公共部分和判断一个链表是否具有回文结构

    数据结构与算法之打印两个有序链表公共部分和判断一个链表是否具有回文结构 目录 打印两个有序链表公共部分 判断一个链表是否具有回文结构 1. 打印两个有序链表公共部分 1.问题描述 思路:Node1和N ...

  3. 算法练习day9——190327(“之” 字形打印矩阵、在行列都排好序的矩阵中找数、打印两个有序链表的公共部分、判断一个链表是否为回文结构)

    1."之" 字形打印矩阵 [题目] 给定一个矩阵matrix, 按照"之" 字形的方式打印这个矩阵, 例如: 1 2 3 4 5 6 7 8 9 10 11 1 ...

  4. 刷题日记-判断一个链表是否为回文结构

    判断一个链表是否为回文结构 描述 给定一个链表,请判断该链表是否为回文结构. 回文是指该字符串正序逆序完全一致. 数据范围: 链表节点数 0≤n≤10510^5105,链表中每个节点的值满足∣val∣ ...

  5. 牛客题霸 [判断一个链表是否为回文结构] C++题解/答案

    判断一个链表是否为回文结构 题目描述 给定一个链表,请判断该链表是否为回文结构. 题解: 直接将链表内的数据存入string中,然后从两端开始向中间判断即可 代码: /*** struct ListN ...

  6. 判断一个链表是否为回文结构【Java实现】

    题目:给定一个链表的头节点head,请判断该链表是否为回文结构. 如:1 2 1 返回true 1 2 2 1 返回true 1 2 3 返回false 思路一: 利用栈,从左到右遍历链表,然后将每一 ...

  7. 判断一个链表是否为回文结构

    package class_03;import java.util.Stack;/*** * 判断一个链表是否为回文结构[题目] 给定一个链表的头节点head,请判断该链表是否为回文结构. 例如: 1 ...

  8. (十三)判断一个链表是否是回文结构

    判断一个链表是否是回文结构 判断一个链表是否是回文结构 栈实现 栈+快慢指针 有限个变量 判断一个链表是否是回文结构 [题目]给定一个单链表的头结点,请判断该链表是否为回文结构 [要求]如果链表长度为 ...

  9. 判断一个链表是否为回文结构-Java:解法三

    分享一个大牛的人工智能教程.零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击http://www.captainbed.net package live.every.day.Pro ...

  10. NC96 判断一个链表是否为回文结构

    NC96 判断一个链表是否为回文结构 描述 给定一个链表,请判断该链表是否为回文结构. 示例1 输入: [1] 复制 返回值: true 复制 示例2 输入: [2,1] 复制 返回值: false ...

最新文章

  1. 激光雷达和毫米波雷达
  2. 从60多场技术面试中,我总结了这份面试经验
  3. Spring Boot 2.x基础教程:JdbcTemplate的多数据源配置
  4. 用计算机怎么录资料,如何在短时间内快速录入大量数据 -电脑资料
  5. 《sql语句练习1》
  6. php curl密码控件,检索通过curl传递的用户名,密码参数 - php
  7. chmod命令使用详解
  8. 关于如何提高代码执行效率。
  9. python format函数实例_【Python】-String的Format格式规约函数及实例
  10. java Socket(TCP)编程小项目
  11. springboot下使用拦截器和过滤器
  12. axios官方文档——中文版
  13. java 读usb口 用POS-58 90U 打印
  14. java pdf合并_如何实用Java实现合并、拆分PDF文档
  15. 嵌入式应用之UART串口
  16. html5课程总结500字,月考总结500字作文5篇
  17. 八戒帮扶V5微信公众平台任务系统完美运营v1.5.8
  18. 利用matplotlib制作饼图
  19. TOM游戏h5营销案例分析-高空运鸡蛋
  20. 云-阿里云-百科:阿里云

热门文章

  1. Kobe - python元组的使用
  2. GaussDB分布式测试环境搭建
  3. Python编程笔记6字典
  4. 摄像机模型——针孔成像
  5. 微信公众号开发(6)关注事件
  6. if:听说,你很勇哦?
  7. 关于Airflow跨DAG依赖总结
  8. openoffice osl模块学习1
  9. 分带在中央经线在arcgis中的一些表示
  10. 向量运算-叉积,点积