题目详情
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
要求: O(n) 时间复杂度和 O(1) 空间复杂度解决此题
解题
结合回文序列的特点,进行如下想法
三步:
- 快慢指针寻中点(考虑奇偶分别进行处理)
- 前半段reverse
- 两段链表进行挨个比较
缺陷(对原数据进行了修改,最终没有改回去) 具体的思路我在代码中写的十分清楚了
此处就是将三步进行综合,这三步其实拆开都可以作为单独的一道简单题。其中难点在于链表的空指针异常。
此处除了综合三步之外,另外一难点在于,如何区分对待奇偶长度的链表,这点很重要。
对待奇数长度,我们应该将中间的点丢弃,而对待偶数长度,直接拆分。
我的代码优势在于思路十分清晰简洁,运行速度快,而缺点亦很明显,修改了数据,同时将奇数中间点删除了,jvm会直接gc它,这很好改,但是我懒得改了。
下面直接上代码,代码中有详细的注释
class Solution {
//O(n)的时间,O(1)的空间
//思路有了,分成3步
//首先找到中点,前中点,用快慢指针来寻找O(n)
//然后将中点所在的前半段链表进行翻转O(n)
//之后进行从中点和中点的下一个进行挨个的比较O(n)
//总体的时间复杂度是O(3n),空间复杂度是O(1)
//当然也有另外一个想法,就是用字符串来记录结果
//但是我不确定是否用字符串可以算作是一个常数空间,这个我搞不懂
public boolean isPalindrome(ListNode head) {
if(head==null || head.next==null)return true;
//查询到第二段的开头
ListNode head2 = findMid(head);
//将前半截进行逆序
ListNode head1 = reverseList(head);
//进行对比,看是否相等
while(head1!=null&&head2!=null){
if(head1.val!=head2.val)return false;
head1 = head1.next;
head2 = head2.next;
}
return head1==head2;
}
/*
*利用快慢指针寻找到第二段的开头
*/
private ListNode findMid(ListNode head){
ListNode fast = head.next, low = head, pre = null;
//偶数时,fast.next==null,奇数时,fast==null
//所以需要对这个进行不同的处理
while(fast!=null && fast.next!=null){
pre = low;
fast = fast.next.next;
low = low.next;
}
//针对奇数or偶数进行处理
if(fast==null){
pre.next = null;
return low.next;
}
else{
pre = low.next;
low.next = null;
return pre;
}
}
/*
*反转链表
*/
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;
}