一.题目描述
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
二.题目解析
public static boolean isPalindrome(ListNode head) {
/*暴力法遍历+栈,时间复杂度O(n),空间复杂度O(n)
* */
ListNode p1 = head,p2 = head;
int count = 0;
Stack<ListNode> stack = new Stack<>();
//统计出所有的节点数
while (p2 != null){
count++;
p2 = p2.next;
}
//前半部分压栈
for (int i = 0; i < count / 2; i++) {
stack.push(p1);
p1 = p1.next;
}
//如果是奇数个节点就跳过中间那个节点
if(count % 2 == 1){
p1 = p1.next;
}
//弹栈依次比较
while (!stack.isEmpty() && p1 != null){
if(stack.pop().val != p1.val){
return false;
}
//p1指针顺序往后遍历
p1 = p1.next;
}
//经过上述处理两边的数量一定是相等的,故最后直接return true即可
return true;
}
2.
ListNode left;
boolean isPalindrome2(ListNode head) {
/*递归,时间复杂度O(n),空间复杂度O(n)
递归过程中实际上也相当于把节点压栈,不过这个栈指的是递归函数的堆栈
eg.1->2->2->1 压栈顺序:traverse(1)->traverse(2)->traverse(2)->traverse(1)
left按照顺序遍历的顺序,在弹栈的过程中right指针等同于逆序遍历的效果,二者再相比。
* */
left = head;
return traverse(head);
}
boolean traverse(ListNode right) {
if (right == null) return true;
boolean res = traverse(right.next);
// 此轮结果=前轮结果&&此轮两个对称的元素比较的结果
res = res && (right.val == left.val);
//left指针顺序往后
left = left.next;
return res;
}
public static boolean isPalindrome1(ListNode head) {
/*快慢指针法,时间复杂度 O(N),空间复杂度 O(1)
* */
ListNode fast = head,slow = head;
//slow最终指向位置即为终点位置
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
//如果链表长度是奇数个,slow还需要前进一位
if(fast != null){
slow = slow.next;
}
ListNode newHead = null;
//翻转从slow开始的部分
slow = reverse(slow);
//fast重新指向链表头
fast = head;
//前半部分和翻转后的后半部分依次比较
while (slow != null){
if(fast.val != slow.val){
return false;
}
fast = fast.next;
slow = slow.next;
}
return true;
}
private static ListNode reverse(ListNode slow) {
/*翻转从slow开始的部分
* */
ListNode cur = slow,nextCur = null,prev = null;
while (cur != null){
//记录下个要处理的节点
nextCur = cur.next;
//实现翻转
cur.next = prev;
//更新prev
prev = cur;
//更新要处理的节点
cur = nextCur;
}
return prev;
}
注:类似于二叉树,
void traverse(TreeNode root) {
// 前序遍历代码
traverse(root.left);
// 中序遍历代码
traverse(root.right);
// 后序遍历代码
}
链表也有前序和后序遍历
模板如下:
void traverse(ListNode head) {
// 前序遍历代码
traverse(head.next);
// 后序遍历代码
}
参考文章:
https://labuladong.gitbook.io/algo/mu-lu-ye-1/mu-lu-ye/pan-duan-hui-wen-lian-biao