Description
Follow Up
Solution 1(C++)
/**
* 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) {
vector<int> nodeint;
while(head != NULL){
nodeint.push_back(head->val);
head=head->next;
}
for(int i=0; i<nodeint.size()/2; i++){
if(nodeint[i] != nodeint[nodeint.size()-1-i])
return false;
}
return true;
}
};
Solution 2(C++)
/**
* 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==NULL||head->next==NULL)
return true;
ListNode* slow=head;
ListNode* fast=head;
while(fast->next!=NULL&&fast->next->next!=NULL){
slow=slow->next;
fast=fast->next->next;
}
slow->next=reverseList(slow->next);
slow=slow->next;
while(slow!=NULL){
if(head->val!=slow->val)
return false;
head=head->next;
slow=slow->next;
}
return true;
}
ListNode* reverseList(ListNode* head) {
ListNode* pre=NULL;
ListNode* next=NULL;
while(head!=NULL){
next=head->next;
head->next=pre;
pre=head;
head=next;
}
return pre;
}
};
算法分析
解法一: 这种做法实质还是将链表转换为基本的数据结构vector来进行题目解答。非常基础的一种做法,也很简单。可以用来练练手,比如如何获取结点的值。
解法二: 解法二是重点需要学习的方法,首先,对于链表要明白一个概念,它与一般的容器不一样,它不是“连续的”。它是以一个一个的结点表现的,也就是说,当前有这样一个结点,我也只知道有这样的一个结点,其他的结点如何,不知道,链表中一共有多少个结点有多少也不知道。只知道当前这样的结点,结点有当前的值与下一个结点。
所以,链表的遍历只能通过循环不断去找一个结点的下一个结点。一直重复知道结点为NULL。而单向结点就只知道下一个结点,上一个结点不知道。这就增加了判断一个链表是否为回文链表的难度。
说回算法本身,其实这里解法二用到的方法是第二次见了,双指针——龟兔赛跑算法。第一次见可参考:LeetCode-141. Linked List Cycle。 借用龟兔赛跑算法,可以很轻松的理解141题中如何判断一个链表是否循环。如果循环,两个速度不一样的指针跑了足够多的圈,那么就一定会相遇。如果不循环,那么一个跑到终点了,另一个还在赛道上。
所以,141题利用双指针龟兔赛跑的方法来判断一个链表是否为循环链表,这里可以利用双指针龟兔赛跑方法来获取一个链表的长度的几分之几的结点。什么意思呢?
假如一个快指针,一个慢指针,快指针的速度是慢指针的两倍,即:
fast=fast->next->next;
slow=slow->next;
那么,当fast跑完整个链表,这时慢指针正好停留在链表中央,也就是二分之一处。
同理,如果快指针是慢指针的三倍速度,那么慢指针最终将停留在三分之一处。如果速度比为3:2,就停留在三分之二处。这个还是挺有意思的。
所以,解法二利用这种方法,将slow停留在中间,然后将后半段反转链表,这样,同时从head与slow同时查询下一个结点,如果全都相同,说明回文成立,否则不成立。
反转链表通过子函数实现,具体可以参考: LeetCode-206. Reverse Linked List。 要说的有两点:一、子函数传入只是头结点;二、子函数返回值也是头结点。传入:1->2->3->4->5,返回:1<-2<-3<-4<-5,传入为1,传出为5.
程序分析
程序编写没太好说的,解法二关键还在于反转函数的编写。这几道链表的题都很基础,也很重要。