LeetCode #234. Palindrome Linked List 链表 栈 链表逆置

Description


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?



思路


解法一

用一个栈将全部元素存储起来,记录回文串的中点。从序列的两边往中间遍历元素,同时比较两者是否相等,如果不相等说明就不是回文串,反之则是回文串。

需要额外注意的是,中点需要根据奇偶情况而定,偶数时需要额外减一。

时间复杂度:O(n)
空间复杂度:O(n)

耗时 24 ms, faster than 69.10%, Memory 14.8 MB

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (!head) return true;

        stack<int> stk;
        for (ListNode *ptr = head; ptr != nullptr; ptr = ptr->next) {
            stk.push(ptr->val);
        }

        // Only need to compare the half of the palindrome
        int palindrome_pos = stk.size() & 1 ? stk.size() / 2 : stk.size()/2 - 1;
        int i = 0;
        ListNode *ptr = head;
        while (i <= palindrome_pos) {
            if (stk.top() != ptr->val) {
                break;
            }

            stk.pop();
            ptr = ptr->next;
            ++i;
        }

        if (i > palindrome_pos) {
            return true;
        } else {
            return false;
        }
    }
};



解法二

解法一没法应对 follow up,所以我们需要再想想办法。

受到之前做的快慢指针套路题(求是否有环、求中点)的启发,我们可以使用快慢指针思路来记录回文串的中点,而且这么找中点会比解法一更好一点,因为我们不用讨论奇偶性,慢指针停下来的地方一定就是中点。OK,第一个 tricky 的点就解决了。

另一个 tricky 的点是,如何用另一个方法代替栈的“后入先出”的特性?
经过参考博客的启发,我发现了“链表逆置”其实可以在 O(n) 的时间复杂度解决的,那么就可以把回文串的后半部分做一个逆置操作,然后从起点与中点后的第一个位置开始比较,从而判断出这个串是不是回文串。比如"1 2 3 3 2 1",中点是第一个 3,逆置后的序列为"1 2 3 1 2 3",从第一个 1 和第二个 1 开始往后遍历并比较两者的值,从而判断出这个串是不是回文串。

时间复杂度:O(n)

空间复杂度:O(1)

耗时 28 ms, faster than 30.87 %, Memory 14.3 MB

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (!head || !head->next) return true;

        // use "slow-fast point" to get mid point of linked list
        ListNode *slow = head;
        ListNode *fast = head;
        while (fast->next && fast->next->next) {
            fast = fast->next->next;
            slow = slow->next;
        }

        // reverse second half of linked list
        ListNode *last = slow->next;
        while (last->next) {
            ListNode *tmp = last->next;
            last->next = tmp->next;
            tmp->next = slow->next;
            slow->next = tmp;
        }

        // compare the first half and second half
        ListNode *first = head;
        while (slow->next) {
            slow = slow->next;
            if (first->val != slow->val) return false;
            first = first->next;
        }

        return true;
    }
};



参考




posted @ 2020-05-10 13:18  bw98  阅读(152)  评论(0编辑  收藏  举报