zoukankan      html  css  js  c++  java
  • (双指针+链表) leetcode 19. Remove Nth Node from End of List,61. Rotate List,143. Reorder List,234. Palindrome Linked List

    本题是从1开始计数;n一定是合法的。

    能否只遍历一遍链表?

    n = 2, 则要删除4和5。使用两个指针来寻找要删除的区间。

     

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* removeNthFromEnd(ListNode* head, int n) {
            //虚拟头结点
            assert(n>=0);
            ListNode* dummy = new ListNode(0);
            dummy->next = head;
            ListNode* p = dummy;
            ListNode* q = dummy;
            for(int i=0; i<n+1;i++){
                assert(q);
                //将q向后移n+1次
                q = q->next; 
            }
            //p和q之间相差n+1步
            while(q!=NULL){
                p = p->next;
                q = q->next;
            }
            //此时p指向待删除指针的前一个指针
            ListNode* delNode = p->next;
            p->next = delNode->next;
            delete delNode;
            
            ListNode* ret = dummy->next;
            delete dummy;
            
            return ret;
        }
    };

    思路:快慢指针,一开始让fast和slow指向链表的头结点,然后让fast指向链表旋转k位后的头结点,然后fast和slow同时向后移动,直到fast指向原链表的最后一个元素,此时,slow指向新链表最好一个元素,slow->next指向新链表的head。

     注意:需要提前遍历一遍链表,求出其长度n,然后k = k%n

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    //1->2->3->4->5->NULL
    //k=2
    //初始使slow和fast间隔为k
    //fast最终指向原链表最后一个元素(即5),slow指向新链表最后一个元素(即3),slow->next指向新链表的head
    class Solution {
    public:
        ListNode* rotateRight(ListNode* head, int k) {
            if(head==NULL)
                return NULL;
            ListNode* fast = head;
            int n = 0;  //链表长度
            while(fast){
                n++;
                fast = fast->next;
            }
            fast = head;
            ListNode* slow = head;
            k = k%n;
            for(int i=0; i<k; ++i)
                fast = fast->next;
            while(fast->next){
                slow = slow->next;
                fast = fast->next;
            }
            fast->next = head;
            head = slow->next;
            slow->next = NULL;
            return head;
        }
    };

     注意:1)如果 k>n 那么在使p, q移动时容易报错产生空指针。所以需要先遍历一遍链表求出其总长度,然后再 k = k % n。

     2)在遍历链表时注意n初始值的设立。

    3)使用双指针来取得需要旋转的区间。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* rotateRight(ListNode* head, int k) {
            if(head==NULL) return NULL;
            
            ListNode* dummy = new ListNode(-1);
            dummy->next = head;
            ListNode* p = dummy;
            ListNode* q = dummy;
            
            //遍历一遍链表得到总长度
            ListNode* r = head;
            int n = 0;
            while(r != NULL){
                n += 1;
                r = r->next;
            }
            //取余数,防止k比n大的情况
            k = k % n;
            
            if(k == 0) return head;
            
            for(int i=0;i<k;i++){
                assert(q);
                q = q->next;
            }
            while(q->next != NULL){
                p = p->next;
                q = q->next;
            }
            
            //此时p指向需要旋转节点的前一个,q指向最后一个旋转节点
            ListNode* ans = p;
            p = p->next;    //p指向第一个旋转节点
            ans->next = NULL;
            dummy->next = p;
            q->next = head;
            
            ListNode* ret = dummy->next;
            delete dummy;
            return ret;
        }
    };

    思路:获得链表中间的元素后将链表分为左右两个链表,把右链表翻转之后,将两个链表分别穿插。

    使用中间指针。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void reorderList(ListNode* head) {
            if(!head || !head->next|| !head->next->next)
                return;
            //快慢指针 找到链表中点
            ListNode* fast = head, *slow = head;
            while(fast->next && fast->next->next){
                fast = fast->next->next;
                slow = slow->next;
            }
            
            //翻转链表后半段
            ListNode* mid = slow->next;  //链表中点
            slow->next = NULL;
            ListNode* pre = NULL;
            while(mid){
                ListNode* next = mid->next;
                mid->next = pre;
                pre = mid;
                mid = next;
            }
            
            //合并
            while(head && pre){
                ListNode* cur = head->next, *pre_next = pre->next;
                head->next = pre;
                pre->next = cur;
                pre = pre_next;
                head = cur;
            }
            
        }
    };
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void reorderList(ListNode* head) {
            if(!head || !head->next || !head->next->next)
                return;
            
            //快慢指针找到链表中点
            ListNode* p_fast = head;
            ListNode* p_slow = head;
            
            while(p_fast->next && p_fast->next->next){
                p_slow = p_slow->next;
                p_fast = p_fast->next->next;
            }  
            
            //将后一半链表翻转
            ListNode* mid = p_slow->next;
            p_slow->next = NULL;
            ListNode* last = mid, *pre = NULL;
            while(last){
                ListNode* next = last->next;
                last->next = pre;
                pre = last;
                last = next;
            }
             
            //将两个链表合并
            while(pre && head){
                ListNode* next = head->next;
                head->next = pre;
                pre = pre->next;
                head->next->next = next;
                head = next;    
            }
        }
    };
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void reorderList(ListNode* head) {
            
            
            ListNode* dummy = new ListNode(-1);
            dummy -> next = head; 
            
            ListNode* fast = dummy;
            ListNode* slow = dummy;
            
            while(fast!=NULL && fast->next!=NULL){
                slow = slow->next;      //slow最终指向链表的中间节点
                fast = fast->next->next;    
               
            }
            
            //slow这时指向链表的中间节点
            ListNode* ans = slow->next;
            slow->next = NULL;
            
            //翻转第二个链表
            ListNode* last = ans, *pre = NULL;
            while(last)
            {
                ListNode* next = last->next;
                last->next = pre;
                //将后一个节点赋值给前一个节点
                pre = last;
                last = next;
            }
            
            while(pre!=NULL && head!=NULL){
                ListNode* next = head->next;
                head->next = pre;
                pre = pre->next;
                head->next->next = next;
                head = next;      
            } 
        }
        
    };
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void reorderList(ListNode* head) {
            if(!head || !head->next ||!head->next->next)
                return;
            ListNode* fast= head, *slow = head;
            while(fast->next && fast->next->next){
                slow = slow->next;
                fast = fast->next->next;
            }
            
            ListNode* mid = slow->next, *pre = NULL, *next = NULL;
            slow->next = NULL;  //令前半段链表最后一个元素的后继为空
            
            while(mid){
                next = mid->next;
                mid->next = pre;
                pre = mid;
                mid = next;
            }
            
            ListNode *h_n = NULL, *pre_n = NULL;
            while(head && pre){
                h_n = head->next;
                pre_n = pre->next;
                head->next = pre;
                pre->next = h_n;
                head = h_n;
                pre = pre_n;
            }
            
        }
    };

    注意: slow->next = NULL;  //令前半段链表最后一个元素的后继为空

    这句一定要记得写,不然会 time limit !!!!

    回文:正着看和反着看是一样的。

    若是数组实现:则用两个指针,一个从前向后移,一个从后向前移,来分别判断是否对应的元素相同。

    思路1:使用快慢指针找中点的原理,在每次慢指针走一步时都把值存入栈中,然后等到达中点了,链表的前半段都存入栈中了,由于栈先进后出的性质,可以和后半段链表按照回文对应的顺序比较了。

    思路2:若是要采用O(1)的时间复杂度,那就不能使用stack了。可以在找到中点后,将后半段的链表翻转一下,这样就可以按照回文的顺序比较了。

    注意边界条件的判断!

    /**
     * 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 && fast->next->next){
                slow = slow->next;
                fast = fast->next->next;
            }
            
            //翻转后一个链表
            ListNode* last = slow->next, *pre = NULL;
            while(last){
                ListNode* next = last->next;
                last->next = pre;
                pre = last;
                last = next;
            }  //最终pre指向第二个链表的头结点
            
            while(pre){
                if(pre->val != head->val) return false;
                pre=pre->next;
                head = head->next;
            }
            return true;
        }
    };
  • 相关阅读:
    mysql 远程登陆不上
    hdu 5339 Untitled【搜索】
    SqlServer 书目
    passwordauthentication yes
    oracle 11g RAC ocfs2
    Oracle 11g RAC database on ASM, ACFS or OCFS2
    CentOS ips bonding
    Oracle 11g RAC features
    openStack 王者归来之 trivial matters
    openstack windows 2008 img
  • 原文地址:https://www.cnblogs.com/Bella2017/p/10181127.html
Copyright © 2011-2022 走看看