题目描述
请判断一个链表是否为回文链表。
样例
输入: 1->2
输出: false
输入: 1->2->2->1
输出: true
进阶:
你能否用 $O(n)$ 时间复杂度和 $O(1)$ 空间复杂度解决此题?
算法分析
核心思路:找到链表右半部分链,并将右半部分链进行反转,对左半部分链表 和 反转后的右半部分链表 的元素进行一一比较,若都相同则是回文链表
具体方法
- 1、通过快慢指针
slow
和fast
,slow
每次走一步,fast
每次走两步,找到右半部分链,由于不知道链表的元素个数是奇数个还是偶数个,因此统一规则让 右半部分链 比 左半部分链 的元素个数最多多1
个,初始化slow = head
,fast = head.next
,则slow.next
就是右半部分链的开头 - 2、将右半部分链进行反转,由于题目要求空间复杂度是$O(1)$,因此只能用迭代的方式对链表进行反转,反转后记得将
slow.next
指向null
,让左右链表隔离开 - 3、假设左边链表的个数是
x
个,右边链表的个数可能是x
个,也可能是x + 1
个,因此比较x
次,若x
次中链表的元素都一一对应则是回文链表,否则不是回文链表
时间复杂度 $O(n)$
空间复杂度 $O(1)$
Java 代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
static ListNode reverse(ListNode head)
{
ListNode a = head,b = head.next;
while(b != null)
{
ListNode c = b.next;
b.next = a;
a = b;
b = c;
}
head.next = null;
return a;
}
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ListNode slow = head, fast = head.next;
while(fast.next != null && fast.next.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
//将右半部分的链表slow.next进行反转
ListNode right = reverse(slow.next);
ListNode left = head;
slow.next = null;
while(left != null && right != null)
{
if(left.val != right.val) return false;
left = left.next;
right = right.next;
}
return true;
}
}
我想问一下最后这个tail不应该跟着a往前移动吗(ListNode tail = a;传的不是地址吗),为什么这个tail最后还是一开始ListNode tail = a;的最后一个节点的位置
tail
和a
都是一个指针,ListNode tail = a
表示tail
指针和a
指针都指向某个地址,当a
经过移动后指向了其他的地址,与tail
指向的地址就不同了。并不能说a
指向某个地址,就可以看成是将a
指向的原来的地址修改了,这是错误的明白了,谢谢~