来源

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-linked-list/

描述

请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false

示例 2:
输入: 1->2->2->1
输出: true

进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

题解

避免使用234. 回文链表(Palindrome Linked List) - 图1额外空间的方法就是改变输入。
将链表的后半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例,因为使用该函数的人不希望链表结构被更改。

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public boolean isPalindrome(ListNode head) {
  11. if (null == head) {
  12. return true;
  13. }
  14. ListNode firstHalfEnd = endOfFirstHalf(head);
  15. ListNode secondHalfStart = reverseList(firstHalfEnd.next);
  16. ListNode p1 = head;
  17. ListNode p2 = secondHalfStart;
  18. boolean result = true;
  19. while (result && p2 != null) {
  20. if (p1.val != p2.val) {
  21. result = false;
  22. }
  23. p1 = p1.next;
  24. p2 = p2.next;
  25. }
  26. firstHalfEnd.next = reverseList(secondHalfStart);
  27. return result;
  28. }
  29. private ListNode endOfFirstHalf(ListNode head) {
  30. ListNode fast = head;
  31. ListNode slow = head;
  32. while (fast.next != null && fast.next.next != null) {
  33. fast = fast.next.next;
  34. slow = slow.next;
  35. }
  36. return slow;
  37. }
  38. private ListNode reverseList(ListNode head) {
  39. ListNode prev = null;
  40. ListNode curr = head;
  41. while (curr != null) {
  42. ListNode nextTemp = curr.next;
  43. curr.next = prev;
  44. prev = curr;
  45. curr = nextTemp;
  46. }
  47. return prev;
  48. }
  49. }

复杂度分析

  • 时间复杂度:234. 回文链表(Palindrome Linked List) - 图2,其中234. 回文链表(Palindrome Linked List) - 图3指的是链表的大小;
  • 空间复杂度:234. 回文链表(Palindrome Linked List) - 图4,我们是一个接着一个的改变指针;

Notes

  • 该方法的缺点是,在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执执行过程中链表暂时断开。