回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路一: 借助外来的空间
这个题我的初步思路是借助外来的空间,也就不是O(1)的空间复杂度,那么这个就比较简单了,只需要遍历一遍链表,把每个元素存入到数组中,然后看看是不是回文数组就可以了,数组的优势就是内存连续,查找方便,这个就不多解释了,直接上代码
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> v;
ListNode *p = head;
while(p)
{
v.push_back(p->val);
p = p->next;
}
for (int i=0,j=v.size()-1; i<=j;i++,j--)
{
if (v[i]!=v[j])
return false;
}
return true;
}
};
这个速度还是比较快的。但是空间复杂度O(n),毕竟弄了一个数组。
思路二: 快慢指针找中点
这个思路是借鉴人家的一个思路,使用快慢指针,竟然可以找到链表的中点,这个之前是不知道的,这次学到了,就是两个指针开始的时候,都指向第一个元素,之后,往前走,快的指针一次走两步,慢的指针一次走一步,这样的话当快的走到头的时候,慢的正好走到中点位置。 这个想法简直是太好了。 这个题就可以使用这个思想。
就是先找到中点,然后前面的部分逆置,然后前面的一半和后面的一半再比较。这样的话,空间复杂度就是O(1)了。
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (!head || !head->next) return true;
ListNode *slow = head;
ListNode *fast = head;
ListNode *pre=head, *prepre=NULL;
// 快慢指针遍历找中点的同时,把前半部分进行逆置
while (fast && fast->next)
{
pre = slow;
slow = slow->next;
fast = fast->next->next;
pre->next = prepre;
prepre = pre;
}
// 如果是奇数个节点,这时候fast正好是不为空,此时,slow正好是中间位置,需要往后移动一下
if (fast)
slow = slow->next;
// 下面就可以开始比较了,前半部分是pre指向,后半部分是slow指向,如果不一样的话,就不是回文串
while (pre && slow)
{
if (pre->val != slow->val)
return false;
pre = pre->next;
slow = slow->next;
}
return true;
}
};
python代码:
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
dummy = ListNode(-1)
dummy.next = None
fast = slow = head
while fast and fast.next:
temp = slow
slow = slow.next
fast = fast.next.next
temp.next = dummy.next
dummy.next = temp
if fast:
slow = slow.next
p = dummy.next
while p and slow:
if p.val != slow.val:
return False
p = p.next
slow = slow.next
return True
这个快慢指针的思想值得借鉴,见后面的总结。
总结 - 神奇的快慢指针
最后稍微总结一下:快慢指针