@(labuladong的算法小抄)[链表]
leetcode 234. 回文链表
题目描述
解题思路
参考:labuladong的算法小抄P277
空间复杂度o(n)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
/* 左侧指针 */
ListNode left;
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
left = head;
return traverse(head);
}
/* 判断left和right间的链表是否是回文链表 */
private boolean traverse(ListNode right) {
if (right == null) return true;
boolean res = traverse(right.next);
/* 利用后序遍历实现双指针,left从左往右遍历,right从右往左遍历,不断比较是否相等 */
res &= (right.val == left.val);
left = left.next;
return res;
}
}
空间复杂度o(1)
- 找到后半部分链表的头结点。
- 反转后半部分链表。
- 判断是否回文。
- 恢复链表。
- 返回结果。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
/* 用快慢指针找到链表的中点 */
/* 如果是奇数个节点,中点是中间的节点;如果是偶数个节点,中点是中间靠右的节点(即右半部分链表的头结点) */
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
/* 如果fast不为null,说明有奇数个节点,则slow再前进一步,就变成右半部分链表的头结点 */
if (fast != null) {
slow = slow.next;
}
ListNode left = head;
/* 将右半部分链表反转后,right指向右半部分链表的头结点 */
ListNode right = reverse(slow);
while (right != null) {
if (left.val != right.val) {
/* 返回前恢复右半部分链表 */
reverse(slow);
return false;
}
left = left.next;
right = right.next;
}
/* 返回前恢复右半部分链表 */
reverse(slow);
return true;
}
/* 反转以head为头结点的链表,返回新链表的头结点 */
private ListNode reverse(ListNode head) {
/* 用头插法,pre始终指向新链表的头结点,初始新链表为空 */
ListNode pre = null;
/* 不断将cur所指的节点插到新链表的头部 */
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}