题目234:Palindrome Linked List
题目描述:
Given a singly linked list, determine if it is a palindrome.
Could you do it in O(n) time and O(1) space?
题目分析:
给一个链表判断是否是回文,时间复杂度O(n) ,空间复杂度O(1)指的是额外空间相对于输入数据量来说是常数(《严书》),不随着输入规模n的变化而变化。
排除用栈的方法,压入链表中一半的元素,再一一弹栈,比较链表中后面的元素,因为栈作为辅助空间,随着输入规模n的增大而增大。
《剑指offer》面试题5:从尾到头打印链表
有些类似,这个题目可以分为改变链表结构和不改变链表结构两种。
1. 改变链表的结构:将链表后半部分的元素转置,然后一一比较,判断是否是回文;
2. 不改变链表的结构:
1. 将链表的后半部分元素转置
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (head == 0 || head->next == 0)
return true;
ListNode *fast, *slow;
fast = head;
slow = head;
while (fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
}
ListNode *cur, *pre, *pnext;
pre = slow->next;
cur = pre;
pnext = pre->next;
pre->next = 0;
while (pnext) {
cur = pnext;
pnext = pnext->next;
cur->next = pre;
pre = cur;
}
slow->next = cur;
while (cur) {
if (cur->val != head->val) {
return false;
}
cur = cur->next;
head = head->next;
}
return true;
}
};
其实可以将链表后半部分元素转置的过程,定义为一个函数,在判断是否回文结束,再重新将链表后半部分转置回来,链表结构不变化。
快慢指针
链表题目常用快慢指针。快慢指针,快和慢指的是指针每次移动速度的快慢。比如,快指针,每次沿链表移动2,慢指针,每次沿链表移动1。
举几个例子看快慢指针的应用:
(1)判断单链表是否为循环链表:如果单链表有循环链表,那么快指针一定会遇到慢指针,可能第一次不能相遇,但一定会遇到;
(2)在有序链表中寻找中位数:注意是有序链表,快指针速度是慢指针速度的2倍,还要考虑有序链表中结点个数是奇数还是偶数。如果快指针移动x次后指向链表中最好一个结点(1+2x),则链表有奇数个结点,直接返回慢指针指向的结点;如果快指针指向倒数第二个结点,说明链表结点个数是偶数,这时可以根据要求返回上中位数或下中位数或(上中位数+下中位数)的一半。
(3)判断两个链表是否交叉:如果交叉,则从交叉点开始的后面结点两个链表重合,第一次分别遍历两个链表的长度,设置快慢指针,快指针先走。