要求
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
在自己的编程工具中测试就需要新建ListNode 类
public class ListNode {
public int val;
public ListNode next;
ListNode() {}
public ListNode(int x){
val=x;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
思路
方法一:递归
currentNode
指针是先到尾节点,由于递归的特性再从后往前进行比较。frontPointer
是递归函数外的指针。若 currentNode.val != frontPointer.val
则返回 false。反之,frontPointer
向前移动并返回 true。
算法的正确性在于递归处理节点的顺序是相反的(回顾上面打印的算法),而我们在函数外又记录了一个变量,因此从本质上,我们同时在正向和逆向迭代匹配。
下面的动画展示了算法的工作原理。我们定义递归函数名字为 recursivelyCheck
,每个节点都被赋予了标识符以便更好地解释它们。计算机在递归的过程中将使用堆栈的空间,这就是为什么递归并不是 O(1) 的空间复杂度。
//
//
//
//
//
//
//
//
class Solution {
private ListNode frontPointer;
private boolean recursivelyCheck(ListNode currentNode) {
if (currentNode != null) {
//不为空就继续,存储到堆栈中
if (!recursivelyCheck(currentNode.next)) {
return false;
}
//对比最后一位和第一位的值
if (currentNode.val != frontPointer.val) {
return false;
}
frontPointer = frontPointer.next;
}
return true;
}
public boolean isPalindrome(ListNode head) {
frontPointer = head;
return recursivelyCheck(head);
}
}
时间复杂度:O(n),其中 n 指的是链表的大小。
空间复杂度:O(n),其中 n 指的是链表的大小。
方法二:快慢指针
public class LeetCode234 {
public boolean isPalindrome(ListNode head) {
//链表为空或者只有一个默认为回文,返回true
if (head == null || head.next == null){
return true;
}
//定义快慢指针,以及另外两个指针,一个指向头结点,一个指向空节点
ListNode fast = head,slow = head,pre = head,prev = null;
//快慢指针,等快指针到链表的最后,再反转前半部分
while (fast != null && fast.next != null){
pre = slow;
fast = fast.next.next;
slow = slow.next;
//反转,指向头指针的pre指向空指针prev,prev指向下一个节点
pre.next = prev;
prev = pre;
}
//快指针不为空,证明是偶数链表,慢指针后移一位
if (fast != null){
slow = slow.next;
}
while (pre != null && slow != null){
if (pre.val != slow.val){
return false;
}
pre = pre.next;
slow = slow.next;
}
return true;
}
}
下面是官方的代码,消耗的内存少
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;
}
}