判断一个链表是否回文。一看到判断回文第一想到就是一头一尾双指针移动,但单链表尾巴回不来啊,于是自然想到了栈。但一时半会想不出怎么保持指针,上网搜了一下搜出了另一种解法也是用了栈,用了一个慢指针遍历一个快指针每次移动2格间接测出了链表长度,但如果加上之后的慢指针遍历判断时间度应该算O(1.5n)吧,而且空间不是O(1)。鉴于该逻辑比较好理解,我也就顺着这逻辑写了,但总觉得不是leet要求的,一定有更好的。没错,stackoverflow有更好的,总体思想跟我开始想法一样,但人歪果仁实现了,我很服。
第一种解法,AC用了12ms,用静态数组模拟栈,因为用的C不想写栈了,空间较大否则过不了会runtime error:
//bool isPalindrome(struct ListNode* head) {
// bool result = true;
// int n = 10240;
// int stack[n];
// memset(stack, 0, sizeof(int) * n);
// int sp = 0;
//
// struct ListNode myHead = {0, head};
// struct ListNode *slow = &myHead;
// struct ListNode *fast = head;
//
// while (fast != NULL && fast->next != NULL) {
// slow = slow->next;
// stack[sp] = slow->val;
// fast = fast->next->next;
// sp++;
// }
// slow = slow->next; //由于做了个头结点,所以slow要恒下移一位
// if (fast != NULL)
// stack[sp] = slow->val; //fast不为空说明为奇数,则数据栈入数据;否则栈指针要退1指向当前有效数据
// else
// sp--;
// while (slow != NULL) {
// if (slow->val != stack[sp]) {
// result = false;
// break;
// }
// slow = slow->next;
// sp--;
// }
//
// return result;
//}
下面是歪果仁的递归解法,利用了递归相当于栈的特点,而且空间为O(1),很好的解释了leet上算法和解法的有趣,用了递归稍慢,AC要16ms:
int fix_isPalindrome(struct ListNode **root, struct ListNode *head)
{
if(!head)
return 1;
else
{
int res=fix_isPalindrome(root,head->next);
if(res==0)
return 0;
int r=(*root)->val==head->val;
*root=(*root)->next;
return r;
}
}
bool isPalindrome(struct ListNode* head) {
bool result = false;
result = fix_isPalindrome(&head, head);
return result;
}