题目描述
请判断一个链表是否是回文链表。
进阶要求
仅用O(n)的时间复杂度和O(1)的空间复杂度来实现。
回文链表的定义
1—>2—>3—>2—>1、1—>2—>2—>1这两个都是回文链表
1—>2—>3—>2,不是回文链表
解题思路
我们可以借助其他数据结构来帮助我们实现,比如栈,这样明显简单的多。
解法1
因为栈结构先进后出的特点,我们可以挨个让链表的每一个节点入栈,再出栈比对即可。
public boolean isPalindrome1(ListNode head) {
//定义一个栈
Stack<ListNode> stack = new Stack<>();
ListNode node = head;
//挨个遍历链表的节点,并依次压入栈中
while (node != null) {
stack.push(node);
node = node.next;
}
while (!stack.isEmpty()) {
//head不断从头开始遍历,stack不断从尾开始遍历,直到全部遍历结束,如果过程中有不相等的情况,则不是回文链表
if (head.val == stack.pop().val) {
head = head.next;
} else {
return false;
}
}
return true;
}
考虑进阶的要求,O(1)的空间复杂度,也就意味着不能借助其他的数据结构来实现,这里就需要结合我们之前用到过的关于链表反转,找链表中间节点的内容了
解法2
我们可以先通过快慢指针的方式,在O(1)的空间复杂度下找到链表的中间节点,然后从中间节点开始,反转之后的链表,再从反转链表的头部开始与原链表的头部开始遍历,最终便能判断出是否是回文链表
奇数个节点
刚好指向中间节点3
反转后
开始比对
最后直到指向null,元素都相等,则认为是回文链表
偶数个节点
节点2,2都是中间节点
慢指针指向第2个中间节点,快指针指向null
反转后
最后直到反转的链表指针指向null,如果值都相等,则认为是回文链表
public boolean isPalindrome(ListNode head) {
//快慢指针找链表的中间节点
ListNode fastNode = head;
ListNode slowNode = head;
while (fastNode != null && fastNode.next != null) {
fastNode = fastNode.next.next;
slowNode = slowNode.next;
}
//从中间节点开始反转链表
ListNode pre = null;//pre节点为反转链表的头节点
ListNode next;
while (slowNode != null) {
next = slowNode.next;
slowNode.next = pre;
pre = slowNode;
slowNode = next;
}
ListNode right = pre;
ListNode left = head;
//两个节点同时开始遍历
boolean res = true;
while (right != null) {
if (left.val != right.val) {
res = false;
break;
}
left = left.next;
right = right.next;
}
//还原链表,把之前反转的链表再反转回来(为了不改变原链表的结构,所以要把破坏的原链表再还原回来)
ListNode pre2 = null;
ListNode next2;
while (pre != null) {
next2 = pre.next;
pre.next = pre2;
pre2 = pre;
pre = next2;
}
return res;
}