25. k个一组翻转链表

题目
给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序。

示例 :

给定这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5

说明 :

你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

思路
题目的难度在于翻转的长度不再是整个链表的长度了。在确定反转长度的情况下仍然可以利用链表的reverse,用1-2-3-4-5为例,首先反转两个变成2-1-3-4-5,下一次应该反转3和4,利用reverse仍然可以实现,但要注意的是,反转后的顺序4-3,其中的4必须与前面1联系,而3必须与后面的3联系,否则整个链表就断了。另外,最后只剩下一个5时,其长度已经小于要求的长度2了,这时候应该返回NULL,代表与前面的关系不改变。
首先给出改进的reverse函数,其中head表示当前要反转的链表段的起始位置,n-1表示还剩有多少个数没有完成反转,tail表示这段要反转链表反转后的尾部(其实就是反转前此段链表的头部),begin表示此段链表的前一个结点,在完成反转后必须与前一个结点保持联系。

    ListNode* reverse (ListNode* head, int n, ListNode* tail , ListNode* begin)
    {
        if (head && !head->next && n > 1) return NULL;
        if (n == 1)
        {
            if (head && tail)
            {
                tail->next = head->next;
            }
            if (begin)
            {
                begin->next = head;
            }
        }
        else if (head && head->next && n > 1)
        {
            ListNode* temp = reverse(head->next, n - 1, tail, begin);
            if (temp)
            {
                temp->next = head;
            }
            if (!temp)
            {
                return NULL;
            }
        }
        return head;
    }

下面给出调用reverse的代码,首先应该获得第一段反转,如果反转的结果是NULL,说明整个链表的长度都不够,则直接返回原链表即可。否则的话,就找到新链表开始的位置,保存下来,作为最后返回时用。完成第一段反转后,下一段反转的起始应为第一段的末尾的下一个结点,然后继续reverse就ok了。

    ListNode* reverseKGroup2(ListNode* head, int k)
    {
        ListNode* result = head;
        int t = k;
        while (t > 1 && result)
        {
            result = result->next;
            t--;
        }
        ListNode* temp = reverse(head, k, head, NULL);
        if (!temp) return head;
        while (temp && temp->next)
        {
            temp = reverse(temp->next, k, temp->next, temp);
        }
        return result;
    }

你可能感兴趣的:(25. k个一组翻转链表)