234. Palindrome Linked List
Given a singly linked list, determine if it is a palindrome.
Example 1:
Input: 1->2
Output: false
Example 2:
Input: 1->2->2->1
Output: true
Follow up:
Could you do it in O(n) time and O(1) space?
解题思路:
方法一:
首先设置快慢指针fast,slow找出中点mid,分为前半部分和后半部分;再将后半部分反转,反转后前后部分同时顺序遍历并比较确定是否是回文链表。Note:链表奇数时,中心点在后半部分;链表偶数时中心点在前半部分尾部
/*
执行用时 : 24 ms, 在Palindrome Linked List的C提交中击败了94.38% 的用户
内存消耗 : 11.1 MB, 在Palindrome Linked List的C提交中击败了40.26% 的用户
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool isPalindrome(struct ListNode* head){
//特殊情况先行讨论
if(!head || !head->next){
return true;
}
struct ListNode* fast = head;
struct ListNode* slow = head;
struct ListNode* mid = head;
//找中心点,此时slow指向后半部分第一个结点,mid指向前半部分最后一个结点
while(fast != NULL && fast->next != NULL){
mid = slow;
fast = fast->next->next;
slow = slow->next;
}
//反转后半部分
struct ListNode* q = NULL;//保存当前处理结点的后继结点,防止丢失后继结点
fast = slow->next;
while(fast != NULL){
q = fast->next;
fast->next = slow;
slow = fast;
fast = q;
}
//前后部分同时遍历比较是否是回文
fast = head;
while(fast != mid->next){//条件也可以先置mid->next = NULL,再判定while(fast!=NULL)
if(fast->val != slow->val){
return false;
}
fast = fast->next;
slow = slow->next;
}
return true;
}
微调:
/*
执行用时 : 16 ms, 在Palindrome Linked List的C提交中击败了99.78% 的用户
内存消耗 : 11 MB, 在Palindrome Linked List的C提交中击败了48.92% 的用户
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool isPalindrome(struct ListNode* head){
if(!head || !head->next){
return true;
}
struct ListNode* fast = head;
struct ListNode* slow = head;
struct ListNode* mid = head;
while(fast != NULL && fast->next != NULL){
mid = slow;
fast = fast->next->next;
slow = slow->next;
}
//将前半部分与后半部分断开
mid->next = NULL;
fast = slow->next;
while(fast != NULL){
mid = fast->next;//重复利用fast和mid指针,节约空间
fast->next = slow;
slow = fast;
fast = mid;
}
fast = head;
//由于前面已经设置前半部分最后为NULL,所以此处可以直接判定空
while(fast != NULL){
if(fast->val != slow->val){
return false;
}
fast = fast->next;
slow = slow->next;
}
return true;
}
方法二:
定义一个数组A[],将链表值赋值给数组,然后判定数组是否是回文的,即判定链表是否是回文的
/*
执行用时 : 16 ms, 在Palindrome Linked List的C提交中击败了99.78% 的用户
内存消耗 : 11.2 MB, 在Palindrome Linked List的C提交中击败了34.63% 的用户
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool isPalindrome(struct ListNode* head){
struct ListNode* p = head;
int n = 1,k = 1;
//统计链表个数
while(p!=NULL){
n++;p=p->next;
}
//将链表结点值赋值到数组
int A[n];
p = head;
while(p!=NULL){
A[k++] = p->val;
p=p->next;
}
//首尾同时遍历数组A[]确定是否是回文
int i=1,j=n-1;
while(i<j){
if(A[i]!=A[j])return false;
i++;j--;
}
return true;
}
方法三:
将链表看成是每个结点代表一位的数,通过遍历链表把顺序和逆序的数值计算出来,然后再比较两数值是否相等
/*
执行用时 : 20 ms, 在Palindrome Linked List的C提交中击败了98.43% 的用户
内存消耗 : 10.8 MB, 在Palindrome Linked List的C提交中击败了90.48% 的用户
*/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool isPalindrome(struct ListNode* head){
//特殊情况
if(head == NULL || head->next == NULL){
return true;
}
//初始化统计第一个结点值
struct ListNode* p = head->next;
float ordSum = head->val;//统计整个链表顺序时的组合的数值
float revSum = head->val;//统计整个链表逆序时的组合的数值
float i = 1;
//统计剩下结点值
while(p){
ordSum = ordSum*10 + p->val;
i = i*10;
revSum = revSum + p->val *i;
p = p->next;
}
if(ordSum == revSum){
return true;
}
else{
return false;
}
}
后记:
- 方法一还可以通过反转前半部分来实现。此时前半部分的反转和中点的寻找可以如上分开求,也可以在一个循环内边反转边找中点。
- 方法二中如果#define MaxSize INT_MAX int A[MaxSize];会报错,所以上面添加了一个统计链表个数的实现。如果你有更好的方法希望可以评论告知,将不胜感激
- 此题还可以用栈的方法,但不知道leetcode上c语言栈的用法,故没有贴出。感兴趣的你也可以自己定义栈或者寻找调用leetcode系统栈的方法
- 方法三中ordSum定义为int类型时
Line 24: Char 24: runtime error: signed integer overflow: -299381302 * 10 cannot be represented in type 'int' (solution.c)
最后执行的输入:[-31900,22571,-31634,19735,13748,16612,-28299,-16628,9614,-14444,-14444,9614,-16628,-31900,16612,13748,19735,-31634,22571,-28299]
方法三中ordSum定义为 long int类型时
Line 24: Char 24: runtime error: signed integer overflow: -2993799396147191188 * 10 cannot be represented in type 'long int' (solution.c)
贴出一份别人用栈实现的LeetCode提交范例:
//执行时间:60ms
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct my_stack* Stack;
struct my_stack{
int val;
struct my_stack *next;
};
Stack createStack(){
Stack head;
head = (struct my_stack *)malloc(sizeof(struct my_stack));
head->next = NULL;
return head;
}
int isEmpty(Stack s){
return (s->next == NULL);
}
void push(int val,Stack s){
Stack cell;
cell = (struct my_stack *)malloc(sizeof(struct my_stack));
cell->val = val;
cell->next = s->next;
s->next = cell;
}
int pop(Stack s){
Stack topcell;
int element;
if(isEmpty(s))
return NULL;
else{
topcell = s->next;
s->next = topcell->next;
element = topcell->val;
free(topcell);
}
return element;
}
bool isPalindrome(struct ListNode* head) {
if(head == NULL)
return true;
Stack h = createStack();
struct ListNode* l = head;
while(l != NULL){
push(l->val,h);
l = l->next;
}
while(head != NULL){
if( pop(h) == head->val )
head = head->next;
else
return false;
}
return true;
}
此范例仅供参考。