方法一:利用栈结构的解法,时间复杂度O(n),空间复杂度O(k)
1:从左到右遍历链表,如果栈的大小不等于k,就将节点不断压入栈中
2:当栈的大小第一次达到k时,说明第一次凑齐了k个节点进行逆序,从栈中依次弹出
这些节点,并根据弹出顺序依次链接,这一组逆序完成后,需要记录一下新的头部,
同时第一组的最后一个节点(原来是头结点)应该链接下一个节点。
3:步骤2之后,当栈的大小每次达到k时,说明又凑齐了一组应该进行逆序的节点,从
栈中依次弹出这些节点,并根据弹出的顺序重新链接。这一组逆序完成后,该组的第一
个节点(原来是该组最后一个节点)应该被上一组的最后一个节点链接上,这一组的最
后一个节点(原来是该组第一个节点)应该链接下一个节点。然后继续去凑下一组,直
到链表被遍历完成。
第一种方法的空间复杂度略高,我们看第二种解法:
方法二:不需要栈结构,直接在链表中调整。时间复杂度O(n),空间复杂度O(1),是符合
题目要求的解法。
//实现反转链表的指定区间,反转start-end之间的节点,将反转后链表的头结点和尾节
//点保存,记作newStart和newEnd
void reverseList(ListNode *start, ListNode *end,
ListNode *&newStart, ListNode *&newEnd){
ListNode *pNode = start;
ListNode *pre = NULL;
ListNode *pNext = NULL;
newStart = end;
newEnd = start;
/* 此处切记不能写成while(pNode != end->next) */
ListNode *nextNode = end->next;
while (pNode != nextNode){
pNext = pNode->next;
pNode->next = pre;
pre = pNode;
pNode = pNext;
}
}
ListNode *reverseKGroup(ListNode *head, int k) {
ListNode *p = head;
ListNode *newHead = NULL;
int count = 1;
ListNode *pre = NULL, *pNext = NULL;
ListNode *start = head;
while (p){
pNext = p->next;
//如果节点数达到k个
if (count == k){
ListNode *newStart = NULL, *newEnd = NULL;
//反转链表
reverseList(start, p, newStart, newEnd);
//记录新链表的头结点
if (newHead == NULL)
newHead = newStart;
//将pre节点的next域指向反转后链表的头结点
if (pre != NULL)
pre->next = newStart;
//反转后链表尾节点的next域指向下一个节点,继续向后遍历
newEnd->next = pNext;
//用反转后链表的尾节点作为pre,对pre节点更新
pre = newEnd;
//计数器清零,并从新记录新的待反转链表的起始节点start
count = 0;
start = pNext;
}
p = pNext;
count++;
}
//如果链表的长度小于k,那么未发生过反转,
//返回原始链表头结点head,否则返回新头结点
return newHead == NULL ? head : newHead;
}