Given a singly linked list, determine if it is a palindrome.
Follow up:
Could you do it in O(n) time and O(1) space?
Subscribe to see which companies asked this question
解法1:不考虑Follow中O(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) { vector<int> elem; while (head != NULL) { elem.push_back(head->val); head = head->next; } int n = elem.size(); for (int i = 0; i < n / 2; ++i) { if (elem[i] != elem[n - 1 - i]) return false; } return true; } };
解法2:一个O(1)空间复杂度的笨办法就是先扫描一遍链表,统计节点数目。然后两层循环依次比较对应位置节点值。这样时间复杂度在O(n^2),会超时Time Limit Exceeded
/** * 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) { int n = 0; ListNode* curr = head; while (curr != NULL) { ++n; curr = curr->next; } int loop = 0; ListNode* beg = head; while(loop < n / 2) { ListNode* end = head; for(int i = 0; i < n - 1 - loop; ++i) end = end->next; if(beg->val != end->val) return false; ++loop; beg = beg->next; } return true; } };
解法3:题目的Follow要求O(n)的时间和O(1)的空间,因此不能循环多次,且不能使用额外的数据结构。考虑到链表只能从头节点开始往后顺序遍历,而验证是否是回文需要从两头往中间逐一判断。题目提示使用两个指针,那么得到两个什么样的指针,在它们顺序往后移动到尾部就能判断出是否是回文呢?例如1-->2-->3-->4-->3-->2-->1,可以看出,如果是回文链表,那么将链表后半段反转后和前半段是一样的!而反转链表可以在O(n)时间,O(1)空间内完成,因此整个时间复杂度也就在O(n),空间复杂度就在O(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) { int n = 0; ListNode* curr = head; while(curr != NULL) { ++n; curr = curr->next; } ListNode* beg = head; ListNode* end = head; for(int i = 0; i < n / 2 + n % 2; ++i) end = end->next; end = reverseList(end); for(int i = 0; i < n / 2; ++i) { if(beg->val != end->val) return false; beg = beg->next; end = end->next; } return true; } private: ListNode* reverseList(ListNode* head) { ListNode* rHead = NULL; ListNode* pTail = NULL; while(head != NULL) { ListNode* pNext = head->next; if(pNext == NULL) rHead = head; head->next = pTail; pTail = head; head = pNext; } return rHead; } };
或者使用快慢指针寻找中间节点:
/** * 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, *fast = head; while(fast->next != NULL && fast->next->next != NULL) { // 注意判断条件 slow = slow->next; fast = fast->next->next; } ListNode* beg = head, *end = reverseList(slow->next); // 注意后半段的头节点为slow->next while(beg != NULL && end != NULL) { if(beg->val != end->val) return false; beg = beg->next; end = end->next; } return true; } private: ListNode* reverseList(ListNode* head) { ListNode* rHead = NULL; ListNode* pTail = NULL; while(head != NULL) { ListNode* pNext = head->next; if(pNext == NULL) rHead = head; head->next = pTail; pTail = head; head = pNext; } return rHead; } };