234.回文链表(栈+双指针)

193 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

每日刷题第25天 2021.1.20

回文链表

易错点(笔记📒)

链表

  • 空链表
  • 链表中只有一个元素
  • 链表中当前节点cur和调用某节点的next时,一定要判断当前节点是否为空

回文串

  • a b aa(不要遗漏情况)
  • a b b a

题目

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

示例

  • 示例1 image.png
输入: head = [1,2,2,1]
输出: true
  • 示例2 image.png
输入: head = [1,2]
输出: false

提示

  • 链表中节点数目在范围[1, 105] 内
  • 0 <= Node.val <= 9 进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

解法

分析思路

  • 回文串有两种情况符合:
    1. 奇数[1,2,1] 或 [1]
    2. 偶数 [1,2,2,1] 注意⚠️:不要忘记奇数情况

整体的解题思路

奇数举例:[1,2,1]

  • 用快慢指针找到链表的中点,将链表分为两部分[1]和[2,1]
  • 前半部分存入栈stack中,后半部分开头由slow指针指向(小细节:栈中只需要存储当前节点的val值即可)。因此此时的stack = [1], slow = [2,1]
  • 因为链表长度是奇数,需要将slow指针指向下一个节点,slow = [1](长度为奇数时,中间的节点可以和自身形成回文)
  • 此时比较stack = [1] 和 slow = [1]val是否完全相同即可。
  • 补充:链表长度为1,即:[5],这种情况可以提前进行判断,直接返回true

偶数举例:[1,2,2,1]

  • 用快慢指针找到链表的中点,将链表分为两部分[1,2]和[2,1]
  • 前半部分存入栈stack中,后半部分开头由slow指针指向(小细节:栈中只需要存储当前节点的val值即可)。因此此时的stack = [1,2], slow = [2,1]
  • 因为链表长度是偶数,故直接比较stack = [1,2] 和 slow = [2,1]val是否完全相同即可。

代码展示

/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/

/**
* @param {ListNode} head
* @return {boolean}
*/

var isPalindrome = function(head) {
// 快慢指针 + 栈
if (head.next == null) return true;
  let fast = head;
  let slow = head;
  // 开一个栈
  let stack = [];
  // 获取链表的长度
  let len = 0;
  while (fast) {
    len++;
    fast = fast.next;
  }
  fast = head;
  while (fast && fast.next) {
    // 找到尾部,跳出循环
    stack.push(slow.val);
    fast = fast.next.next;
    slow = slow.next;
  }
  
  // 分偶数和奇数的情况
  // 1.奇数情况下,后半段会多一个数字
  let flag = false;
  while (stack && slow) {
    // 链表长度为奇数 且 第一次进入 
    if (len % 2 == 1 && !flag){
      slow = slow.next;
      flag = true;
    }
    if (stack.pop() != slow.val) {
      // 不相等
      return false;
    }
    slow = slow.next;
  }
  return true;
};