设计一种方式检查一个链表是否为回文链表。
样例
1->2->1
就是一个回文链表。
挑战
O(n)的时间和O(1)的额外空间。
解题思路1:
链表比字符串难的地方就在于不能通过坐标来直接访问,而只能从头开始遍历到某个位置。那么根据回文串的特点,我们需要比较对应位置的值是否相等,那么我们首先需要找到链表的中点,这个可以用快慢指针来实现,原理是fast和slow两个指针,每次快指针走两步,慢指针走一步,等快指针走完时,慢指针的位置就是中点。我们还需要用栈,每次慢指针走一步,都把值存入栈中,等到达中点时,链表的前半段都存入栈中了,由于栈的后进先出的性质,就可以和后半段链表按照回文对应的顺序比较了。
需要注意考虑链表数目为奇数与偶数的两种情况,这两种情况处理方法略有不同,具体见代码:
/**
* Definition of singly-linked-list:
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: A ListNode.
* @return: A boolean.
*/
bool isPalindrome(ListNode * head)
{
// write your code here
if(head == NULL || head->next == NULL)
return true;
ListNode * slow = head;
ListNode * fast = head;
stack<int> stk;//装链表前半部分元素,不包括中间元素
stk.push(slow->val);
//快慢指针寻找链表中间元素,如果链表数目为奇数,slow指向正中间元素,如为偶数,slow指向中间偏左一位置元素
while(fast->next != NULL && fast->next->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
stk.push(slow->val);
}
//如果链表数目为奇数,此时stk装了中间元素,所以要剔除掉,维持其性质
if(fast->next == NULL)
stk.pop();
//栈中元素与链表后半部分一位一位比较即可
while(slow->next != NULL)
{
slow = slow->next;
if(slow->val != stk.top())
return false;
stk.pop();
}
return true;
}
};
解题思路2:
这道题的挑战让我们用O(1)的空间,那就是说我们不能使用stack了,那么如果代替stack的作用呢,用stack的目的是为了利用其后进先出的特点,好倒着取出前半段的元素。那么现在我们不用stack了,如何倒着取元素呢。我们可以在找到中点后,将后半段的链表翻转一下,翻转部分链表参见:Lintcode 36. 翻转链表 II。这样我们就可以按照回文的顺序比较了,代码如下:
/**
* Definition for ListNode
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
/**
* @param head: A ListNode.
* @return: A boolean.
*/
public boolean isPalindrome(ListNode head) {
// write your code here
if(head == null)
return true;
//快慢指针寻找链表中间元素,如果链表数目为奇数,slow指向正中间元素,如为偶数,slow指向中间偏左一位置元素
ListNode slow = head;
ListNode fast = head;
while(fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
//拆分链表[head...slow]为前半部分,(slow, null)为后半部分
//node1指向前半部分的头节点,node2指向后半部分的头节点
ListNode node2 = slow.next;
slow.next = null;
ListNode node1 = head;
//对后半部分链表翻转
ListNode pre = null;
ListNode cur = node2;
while(cur != null){
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
//翻转后pre为后半部分根节点
//依次比较节点值大小
while(pre != null && node1 != null){
if(pre.val != node1.val)
return false;
pre = pre.next;
node1 = node1.next;
}
return true;
}
}