25. Reverse Nodes in k-Group

题意

给一个链表和一个数字k,实现每k个节点翻转一次。

思路1

25. Reverse Nodes in k-Group
首先明确在这个任务中,有三个部分

  • 第一个,将每一块k个节点的链表反转,可以使用递归简单的完成。
  • 第二个,之前指向这一块的那个指针现在要指向新的节点了,比如图上,本来指向5的指针要指向7。
  • 第三个,本来7是指向下一个块的第一个元素,现在需要5来指向下一块的最后一个元素(因为下一块也需要进行反转)。
    时间复杂度O(n), 空间复杂度O(k)(递归深度即为所需空间)

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *next, *newhead;//next:下一个k块处理前的首元素,for Task1
                             //newhead:当一个k块处理完了之后,它新的首元素,for Task2 & 3
    ListNode* dfs(ListNode* p, int k)
    {
        if (k == 0)
        {
            next = p->next;//下一次要从新的next处理,在这里更新next,即next是本轮未更新的最后一个节点的next 
            return newhead = p;
        }
        dfs(p->next, k-1)->next = p;//p节点下一个节点的next指向p,完成Task1
        return p;
    }
    ListNode* reverseKGroup(ListNode* head, int k)
    {
        if (!head) return NULL;
        int cnt = 0, i = 1;
        for(ListNode* p = head; p; p = p->next, cnt++);
        ListNode* ret, *pre = NULL, *temp;
        next = head;
        while(i * k <= cnt)
        {
            temp = dfs(next, k-1);//temp是刚处理完的k块新的最后一个节点
            if (!pre) pre = temp;
            else pre->next = newhead, pre = temp;//上次处理完的k块的最后节点指向这一轮k块处理完的新首节点
            if (i == 1) ret = newhead;
            i++;
        }
        if (i != 1) temp->next = next;
        else ret = head;
        return ret;
    }
};

25. Reverse Nodes in k-Group

思路2

上述方法不仅又臭又长,还需要O(k)的空间复杂度,显然不太理想。那么使用单链表逆转的思想,逐段反转,最后再完成Task2和3。使用迭代方式,空间复杂度为O(1)。

代码

/**
 * 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) {
        int cnt = 0, turn = 1;
        for (ListNode* p = head; p ; p=p->next, cnt++);
        ListNode *pre = NULL, *now = head, *next, *newlast = NULL, *ret = head, *st;
        while (turn*k<=cnt)
        {
            st = now;
            for (int i = 0; i < k; i++)
            {
                next = now->next;
                now->next = pre;
                pre = now;
                now = next;
            }
            if (turn == 1) ret = pre, newlast = st;
            else
            {
                newlast->next = pre;
                newlast = st;
            }
            turn++;
            pre = NULL;
        }
        if (newlast) newlast->next = now;
        return ret;
    }
};