题目:
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法一:
将链表依次拷贝到一个vector数组中,然后使用前后双指针判断vector是否符合回文要求。
时间复杂度: O(n)
空间复杂度: O(n)
需要注意的两点:
(1)[ ] 空链表也属于回文链表,所以在函数入口不能加head==null的特例判断;
(2)for循环的终止条件是(start<end),不能写成(start!=end),否则会死循环且数组越界访问。
/**
* 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 == nullptr || head->next == nullptr) return false;
vector<int> v;
while(head != nullptr) {
v.push_back(head->val);
head = head->next;
}
for(int start = 0, end = v.size()-1; start < end; ++start, --end) {
if(v[start] != v[end]) return false;
}
return true;
}
};
解法二:翻转后半部分链表:
时间复杂度: O(n)
空间复杂度: O(1)
注意以下几点:
(1)在对后半部分链表翻转并比较后,要再将其二次翻转恢复链表状态,因此函数的调用者是不希望改变链表本身的;
(2)compare()步骤不能要求在first与second两个指针比较都都变成空,这种情况只有在链表结点数为偶数个时才可能成立,对于奇数个结点的链表,中间的一个结点的值可以为任意值,都满足回文字符串的要求。
思考: 写这道题时使用了“自顶向下”的编程方法,主函数中只写操作流程:split(分前后两段)、reverse(翻转后半段)、compare(比较)、reverse(恢复),细分的功能则放在后面逐个实现。
这样的好处时不会因为一直在细节中纠缠而导致思路不清,最后写出来的代码也是错误百出,难于调试。
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(head == nullptr) return true; //别扭的特例判断,不得不加
ListNode* tail = split(head);
ListNode* halfHead = reverse(tail->next);
tail->next = nullptr; //断链
bool result = compare(head, halfHead);
tail->next = reverse(halfHead); //恢复,二次翻转
return result;
}
ListNode* split(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while(fast->next != nullptr && fast->next->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow; //tail
}
ListNode* reverse(ListNode* head) {
if(head == nullptr || head->next == nullptr) return head;
ListNode* res = reverse(head->next);
head->next->next = head;
head->next = nullptr;
return res;
}
bool compare(ListNode* first, ListNode* second) {
while(first != nullptr && second != nullptr) {
if(first->val != second->val) return false;
first = first->next;
second = second->next;
}
return true;
//(first == nullptr && second == nullptr);
}
};