LeetCode(25)Reverse Nodes in K-Group

183 篇文章 0 订阅
47 篇文章 36 订阅

题目如下

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For example,
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5

题目的意思是,以K个节点为一个单位,在每个单位内部进行单链表的反转。如果进行到最后,还剩下不到K个节点,那么剩下的节点就不进行反转。也可能是一开始,整个链表就不足K个节点,那么整个链表也不进行反转。

分析如下:

可以老实地迭代进行,每K个为一组,逐组处理,如下面的代码第1版,代码第2版。也可以使用一些改进,比如使用递归,如下面的代码第3版。

我的代码(第1版)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void  reverse_range(ListNode* start){ //开始时写成了引用型参数,出错。不仅是没有必要写成引用,而且是必须不能写成引用。
        if(start==NULL||start->next==NULL)
            return;
        ListNode* p=start;
        ListNode* q=start->next;
        ListNode* r=start->next->next;
        while(q!=NULL){
            q->next=p;
            p=q;
            q=r;
            if(r!=NULL)
                r=r->next;
        }
        start->next=NULL;
        return;
    }

    ListNode *reverseKGroup(ListNode *head, int k) {
        ListNode* p_finish=head;
        ListNode* p_start=head;
        ListNode* p_pre=NULL;
        ListNode* p_next_head=NULL;
        ListNode* p_return=NULL;
        while(p_start!=NULL) {
            int count=k;
            while(p_finish->next!=NULL&&count>1){ //记录本段K个节点的头尾
                p_finish=p_finish->next;
                count--;
            }
            if(count!=1){//不足K个,不需要reverse
                if(p_pre==NULL){
                    return p_start;
                }else{
                    p_pre->next=p_start;
                    break;
                }
            }else{ //足够K个,需要reverse
                p_next_head=p_finish->next;记录下一段K个节点的的头
                p_finish->next=NULL;//标记本段的K个节点。
                if(p_pre==NULL){
                    reverse_range(p_start); //反转从start开始到NULL结束的一段
                    p_pre=p_start;
                    p_return=p_finish;
                }
                else
                {
                    reverse_range(p_start);//反转从start开始到NULL结束的一段
                    p_pre->next=p_finish;
                    p_pre=p_start;
                }
            }
            p_start=p_next_head;
            p_finish=p_next_head;
        }
        return p_return;
    }
};

我的代码(第2版)

在做了LeetCode (92) ReverseLinkedList2 这道题目之后,考虑利用这道题目的结果来进行改写本题的代码。如下:

//128ms过大集合
class Solution{
public:    ListNode *reverseBetween(ListNode * & head, ListNode* & new_head, int m, int n) {
        if (head == NULL)
            return NULL;
        ListNode *q = NULL; //q设定为NULL,p设定为head,这样的好处是,接下来可以用(q==NULL)来判断m是否为1,即head节点是否也参与了reverse,即第一段是否为空。
        ListNode *p = head; //
        for(int i = 0; i < m - 1; i++)
        {
            q = p;
            p = p->next;
        }
        
        ListNode *end = p; //第二段反转后的尾节点。
        ListNode *pPre = p;
        p = p->next;
        for(int i = m + 1; i <= n; i++)//从index=m走向index=n,走过n-m步,即i取值范围是[0,n-m),即[0,n-m-1],即[m+1,n]
        {
            ListNode *pNext = p->next;
            
            p->next = pPre;
            pPre = p;
            p = pNext;
        }
        //最后一次循环,p和pNext都指向了第三段的第1个节点。此时不断p是否为空,都可以写为 "end->next = p; "这样就避免了对第三段是否为空的讨论。
        end->next = p;
        if (q) //如果第一段非空
        {
            q->next = pPre;
            new_head=head;
        }else{   //如果第一段为空
            new_head = pPre;
        }
        return new_head;
    }
    
        ListNode *reverseKGroup(ListNode *head, int k) {
            if(head==NULL||k==1)
                return head;
            ListNode* p=head;
            ListNode* q=NULL;
            ListNode* whole_head=NULL;
            ListNode* whole_tail=NULL;
            while(p!=NULL){
                ListNode* k_start=p;
                ListNode* k_end=NULL;
                int count=0;
                for(count=0;(p!=NULL&&count<k);count++){ 
                    //p取值范围从m到n+1,q取值范围从m到n,即p指向超出末端的下一位。保留下一次反转的起始节点
                    q=p;
                    p=p->next;
                }
                if(count!=k){ //不足K个
                    if(whole_head==NULL){
                        whole_head=k_start;
                        whole_tail=k_end;
                    }else{
                        whole_tail->next=k_start;
                        whole_tail=k_end;
                    }
                }else{ //足够K个
                    reverseBetween(k_start,k_end,1,k);
                    if(whole_head==NULL){
                        whole_head=k_end;
                        whole_tail=k_start;
                    }else{
                        whole_tail->next=k_end;
                        whole_tail=k_start;
                    }
                }

            }
            return whole_head;
    }
}

我的代码(第3版) 因为使用递归一般都会使得代码更加简洁,所以本题也可试试使用递归来解决,果然代码一下子短多了。

//108ms过大集合
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode * reverseKGroup(ListNode *head, int k) {
        ListNode* whole_head=NULL;
        ListNode* pre=NULL;
        ListNode* cur=head;
        int count=0;
        while(count<k&&cur!=NULL){
            pre=cur;
            cur=cur->next;
            count++;
        }
        if(count==k){
            ListNode* p=head;
            ListNode* q=head->next;
            ListNode* r=NULL;
            while(q!=cur){
                r=q->next;
                q->next=p;
                p=q;
                q=r;
            }
            whole_head=p;
            head->next=reverseKGroup(cur,k);
        }else{
            whole_head=head;
        }
        return whole_head;
    }
};

update: 2015-01-03 和上面的第三版(递归版)基本一样

// 132ms
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

class Solution {
public:
    ListNode *reverseKGroup(ListNode *head, int k) {
        if(k == 0 || k==1 || head == NULL)
            return head;
        ListNode* current = head;
        int count = k;
        while (count > 0) {
            if (current == NULL) 
                break;
            current = current->next;
            --count;
        }
        if (count > 0) 
            return head;
        ListNode* previous = head;
        ListNode* next = head->next;
        current = head;
        count = k;
        while (count > 1) {
            previous = current;
            current = next;
            if(next != NULL)
                next = next->next;
            current->next = previous;
            --count;
        }
        head->next = NULL;
        count = k;
        head->next = reverseKGroup(next, count);
        return current;
        
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值