zoukankan      html  css  js  c++  java
  • [LeetCode]81. Palindrome Linked List回文链表

    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;
        }
    };
  • 相关阅读:
    使用递归,计算斐波那契数列
    Javascript模块化编程 require.js使用详解
    逻辑很重要:一句sql语句的事,自己却想了半天,绕了个大弯子
    select options常用操作
    select 下拉菜单Option对象使用add(elements,index)方法动态添加
    $().change事件
    jQuery验证控件jquery.validate.js使用说明
    copy(source,destination)拷贝文件
    Linux常用命令
    纯js实现分页
  • 原文地址:https://www.cnblogs.com/aprilcheny/p/4966241.html
Copyright © 2011-2022 走看看