[leetcode][list] Reverse Nodes in k-Group

本文介绍了一种链表操作算法,实现K个一组的链表反转,仅遍历一次链表并允许常数内存使用。

题目:

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


/**
 * 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 (NULL == head || NULL == head->next || k <= 1) return head;
	ListNode *pGroupFirst = NULL;//指向反转后K元组的第一个节点
	ListNode *pGroupLast = NULL;//指向反转后K元组的最后一个节点
	//只有最后一组可能不足k个字符,isNotLastGroup作为循环结束标志
	bool isNotLastGroup = reverseK(head, k, pGroupFirst, pGroupLast);//反转第一个k元组
	ListNode *headNew = pGroupFirst;//指向新链表的第一个节点
	ListNode *pLast = pGroupLast;//指向当前新链表的最后一个节点
	ListNode *pCur = pGroupLast->next;//指向当前节点
	while (isNotLastGroup && pCur){//还没到最后一组且当前节点不为空
		isNotLastGroup = reverseK(pCur, k, pGroupFirst, pGroupLast);//反转k
		pLast->next = pGroupFirst;//连入原链表
		pLast = pGroupLast;//K元组最后一个节点就是新链表最后一个节点
		pCur = pGroupLast->next;//当前节点变为K元组的下一个节点
	}
	return headNew;
}
private:
//若从start开始存在K个节点,则反转从start开始的k个节点,first指向反转后的第一个节点,last指向反转后的最后一个节点;若不足k个节点,则不反转, 返回值表示链表是否反转过了。
//由于只遍历链表链表一次,所以在事先并不知道是否足够k个节点,所以在反转过程中若发现不足k个节点,再通过调用自己反转回来,由于反转了两次,效果就像没反转过一样。使用这种方法,只有不足K个节点的元组(只有最后一组)需要遍历两次。
bool reverseK(ListNode *start, int k, ListNode *&first, ListNode *&last){
	//注意:无论什么情况,都应根据情况对first和last赋以合适的值
	if (NULL == start) {//当前链表为空,置first和last为空
		first = last = NULL;
		return false;
	}
	if (NULL == start->next){//当前链表只有一个节点,first和last都指向该节点
		first = last = start;
		return false;
	}
	if (1 == k){ //k==1说明不用任何反转,first和start指向同一个节点,遍历链表使last指向最后一个节点
		first = start;
		while (start){
			last = start;
			start = start->next;
		}
		return false;
	}
	ListNode *pCur = start->next ;
	ListNode *pNext = start->next->next;
	int cnt = 1;
	first = last = start;//first和last都初始化为start
	last->next = NULL;//last->next初始化为NULL,遍历K个节点后再使其指向K元组的下一个节点(足够k个节点)
	while (cnt < k && pCur){
		ListNode *pNext = pCur->next;//暂存pCur的下一个节点
		pCur->next = first;//pCur连入新链表
		first = pCur;//更新新链表第一个节点
		pCur = pNext;//更新当前节点为原pCur的下一个节点
		++cnt;//节点计数器加1
	}	
	if (cnt == k){
		last->next = pCur;//pCur指向K元组的下一个节点
		return true;
	}
	else{//不足k个节点,再反转回来
		reverseK(first, cnt, first, last);//last->next = NULL,和last的初值相等,所以不必再赋值
		return false;
	}
}
};

简化代码:

/**
 * 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 (NULL == head || NULL == head->next || k <= 1) return head;
	ListNode *p = head->next, *headNew = head;
	head->next = NULL;//head成为最后一个节点
	int i = 1;
	while (i < k && NULL != p){//翻转前k个节点
		ListNode *q = p->next;//将当前节点加入处理后链表成为新headNew
		p->next = headNew;
		headNew = p;
		p = q;
		++i;
	}
	if (i == k) head->next = reverseKGroup(p, k);//递归翻转后面的部分。注headNew肯定不为NULL
	else{
		//剩余节点个数少于k,再翻转回去,注意此时要以剩余节点个数为k
		headNew = reverseKGroup(headNew, i);
	}
	return headNew;
}
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值