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;
        }
    };
  • 相关阅读:
    linux free
    uptime
    简述负载均衡&CDN技术(转)
    大胆地去做自己坚信的事情,去做不伤害国家和客户的事情 做企业一定要专注。为企业制定战略目标,绝对不能超过三个。超过三个,你就记不住了,员工也记不住
    同一路由器不同vlan之间的通信(一)
    计算机基础之计算机网络与安全
    LayoutInflater的使用
    插入排序
    Java NIO与IO
    高速排序算法
  • 原文地址:https://www.cnblogs.com/Bella2017/p/10181127.html
Copyright © 2011-2022 走看看