回文链表(二十五)

一、题目描述

这是 LeetCode 上的第二百三十四题:回文链表,难度为 简单

Tag:「链表」、「双指针」

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

示例 1:

image.png

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

示例 2:

image.png

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

提示:

1、链表中节点数目在范围[1, 10^5] 内

2、0 <= Node.val <= 9

二、解题思路

思路:

我们可以将链表的后半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例,但是使用该函数的人通常不希望链表结构被更改。

该方法虽然可以将空间复杂度降到 O(1),但是在并发环境下,该方法也有缺点。在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执行过程中链表会被修改。

整个流程可以分为以下五个步骤:

1、找到前半部分链表的尾节点。

2、反转后半部分链表。

3、判断是否回文。

4、恢复链表。

5、返回结果。

执行步骤一,我们可以计算链表节点的数量,然后遍历链表找到前半部分的尾节点。

我们也可以使用快慢指针在一次遍历中找到:慢指针一次走一步,快指针一次走两步,快慢指针同时出发。当快指针移动到链表的末尾时,慢指针恰好到链表的中间。通过慢指针将链表分为两部分。

若链表有奇数个节点,则中间的节点应该看作是前半部分。

步骤二可以使用反转链表来反转链表的后半部分。

步骤三比较两个部分的值,当后半部分到达末尾则比较完成,可以忽略计数情况中的中间节点。

步骤四与步骤二使用的函数相同,再反转一次恢复链表本身。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null) {
return true;
}

// 找到前半部分链表的尾节点并反转后半部分链表
ListNode firstHalfEnd = endOfFirstHalf(head);
ListNode secondHalfStart = reverseList(firstHalfEnd.next);

// 判断是否回文
ListNode p1 = head;
ListNode p2 = secondHalfStart;
boolean result = true;
while (result && p2 != null) {
if (p1.val != p2.val) {
result = false;
}
p1 = p1.next;
p2 = p2.next;
}

// 还原链表并返回结果
firstHalfEnd.next = reverseList(secondHalfStart);
return result;
}

private ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}

private ListNode endOfFirstHalf(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}

复杂度分析:

1、时间复杂度:O(n),其中 n 指的是链表的大小。

2、空间复杂度:O(1)。我们只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)。

三、总结

本道算法题难度为简单,如果对链表不熟悉,那实现起来会相当困难,因此我们要先对链表有足够的熟悉,掌握链表一些常见基础的算法如:反转链表,快慢指针。然后注意细节,每一步思路都要很清晰,方能解决此需求。

好了,本篇文章到这里就结束了,感谢你的阅读🤝


回文链表(二十五)
https://sweetying520.github.io/2022/08/29/A25-回文链表(二十五)/
作者
sweetying
发布于
2022年8月29日
许可协议