「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」
1、题目
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:
输入:head = [1,2,2,1]
输出:true
示例 2:
输入:head = [1,2]
输出:false
提示:
- 链表中节点数目在范围
[1, 105]内 0 <= Node.val <= 9
进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
2、思路
(链表操作)
假设初始的链表是 L1→L2→L3→…→Ln。
分两步处理:
-
找到链表的中点节点,将其后半段的指针都反向,变成:L1→L2→L3→…→L⌈n/2⌉←L⌈n/2⌉+1←…←Ln;
- 然后用两个指针分别从链表首尾开始往中间扫描,依次判断对应节点的值是否相等,如果都相等,说明是回文链表,否则不是。
- 最后再将整个链表复原。
注意:
1、我们选取链表的中点节点为 下取整,n是链表的节点个数。
2、如果一个链表是奇数个节点(假设为5个节点),将其后半段翻转完后的链表为:
3、如果一个链表是偶数个节点(假设为4个节点),将其后半段翻转完后的链表为:
连接左右链表节点之间的指向是双向的
4、具体实现细节看代码
空间复杂度分析: 链表的迭代翻转算法仅使用额外 的空间,所以本题也仅使用额外 的空间。
时间复杂度分析: 整个链表总共被遍历4次,所以时间复杂度是 。
3、c++代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
int n = 0 ; //统计节点的个数
for(ListNode *p = head ; p ; p = p->next) n++;
if(n <= 1) return true; //节点数<=1的一定是回文链表
//找到中点节点,由第一个节点跳(n+1)/2 -1步到达中点节点
ListNode* a = head;
for(int i = 0; i < (n+1)/2 - 1; i++) a = a->next; //a指针指向链表中点
ListNode* b = a->next; //b指针指向链表中点的下一个节点
while(b) //将链表的后半段反向
{
ListNode* next = b->next; //保留b的next节点
b->next = a;
a = b, b = next;
}6
//此时a指向链表的尾节点,我们让b指向链表的头节点
b = head;
ListNode* tail = a; //保留一下尾节点
bool res = true;
for(int i = 0; i < n/2; i++) //判断是否是回文链表
{
if(b->val != a->val)
{
res = false;
break;
}
b = b->next;
a = a->next;
}
//将链表复原,后半段链表翻转
//a指向尾节点,b指向a的下一个节点
a = tail, b = a->next;
for(int i = 0; i < n/2; i++)
{
ListNode* next = b->next;
b->next = a;
a = b , b = next;
}
tail->next = 0;
return res;
}
};
4、Java代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
static ListNode reverse(ListNode head)
{
ListNode a = head,b = head.next;
while(b != null)
{
ListNode c = b.next;
b.next = a;
a = b;
b = c;
}
head.next = null;
return a;
}
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ListNode slow = head, fast = head.next;
while(fast.next != null && fast.next.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
//将右半部分的链表slow.next进行反转
ListNode right = reverse(slow.next);
ListNode left = head;
slow.next = null;
while(left != null && right != null)
{
if(left.val != right.val) return false;
left = left.next;
right = right.next;
}
return true;
}
}
原题链接: 234. 回文链表