方法1 栈
使用出栈入栈的方法,如果是回文结构,则出栈入栈的顺序肯定一致。
时间复杂度:O(N)
空间复杂度:O(N)
public static boolean isPalindrome(Node head) {
Stack<Node> stack = new Stack<>();
Node cur = head;
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
cur = head;
while (!stack.empty()) {
if (stack.pop().value != cur.value) {
return false;
}
cur = cur.next;
}
return true;
}
方法2 快慢指针
使用快慢指针找到链表的中点位置,然后反转链表的后半部分,迭代判断头节点和反转后的头结点,每个值都一致,则是回文。
时间复杂度:O(N)
空间复杂度:O(1)
public static boolean isPalindrome(Node head) {
if (head == null || head.next == null) {
return false;
}
// 当存在2个节点的时候,直接判断节点的值
if (head.next.next == null) {
return head.value == head.next.value;
}
// 节点数量
int count = 3;
// 慢指针
Node slow = head.next;
// 快指针
Node quick = head.next.next;
while (quick.next != null) {
// 当下一个节点的下一个节点为空时则表明此链表为计数链表,因为不是以2的倍数扩张。
if (quick.next.next == null) {
quick = quick.next;
count += 1;
} else {
// 否则
count += 2;
slow = slow.next;
quick = quick.next.next;
}
}
// 如果数量是偶数,并且中间2个数不相等,则此链表不是回文
if (count % 2 == 0 && slow.value != slow.next.value) {
return false;
} else {
Node left = head;
// 反转链表
Node pre = null;
Node cur = slow.next;
while (cur != null) {
Node next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
Node right = pre;
/**
* 当左边节点不等于中间节点
* 并且右边节点不等于中间节点(偶数时为中间节点的下一个节点)
*/
while (left != slow && (count % 2 == 0 ? right != slow.next : right != slow)) {
// 如果值不相等则不是回文
if (left.value != right.value) {
return false;
}
left = left.next;
right = right.next;
}
// 再次反转链表,恢复原有结构
Node pre2 = null;
Node cur2 = pre;
while (cur2 != null) {
Node next = cur2.next;
cur2.next = pre2;
pre2 = cur2;
cur2 = next;
}
}
return true;
}