LeetCode25 k个一组链表反转

21 篇文章 0 订阅
11 篇文章 0 订阅
class Solution {
public:
	ListNode* popstack(stack<ListNode*>& st, ListNode* left, ListNode* right) {
		if (left != NULL) {
			left->next = st.top();
		}
		ListNode* ccc = st.top();
		st.pop();
		ListNode* next = NULL;
		while (!st.empty()) {
			next = st.top();
			st.pop();
			ccc->next = next;
			ccc = next;
		}
		ccc->next = right;
		return ccc;
	}
	ListNode* reverseKGroup(ListNode* head, int k) {
		if (k < 2) {
			return head;
		}
		stack<ListNode*>st;
		ListNode* newhead = head;
		ListNode* cur = head;
		ListNode* pre = NULL;
		ListNode* next = NULL;
		while (cur != NULL) {
			next = cur->next;
			st.push(cur);
			if (st.size() == k) {
				pre = popstack(st, pre, next);
				newhead = newhead == head ? cur : newhead;
			}
			cur = next;
			//cur = cur->next;此处没想明白为什么会出错,先跳过
		}
		return newhead;
	}
};

做题思路

  1. 将k个元素压入栈中
  2. 将k个元素弹出完成逆序
  3. 连接,将弹出的与之前原链表中的元素相连,应该如何记录两个前后节点呢
  4. k小于2,直接返回头指针

代码细节实现

  1. 主函数中先定义新的头节点,用于返回完成后的链表;当前节点,用于遍历整个链表,完成入栈这些操作;pre节点,保存当前栈中这组元素的前驱节点;next节点,保存当前栈中这组元素的后继节点。
  2. 弹栈函数应该做什么工作,判断前驱节点left是否为空,若为空说明是整个链表的第一组元素,若不为空,则将栈顶的元素作为前驱节点left的后继。再取一个变量获取栈中弹出的元素,将弹出的元素与之前弹出的元素相连。最终返回栈底的元素,将这个元素赋值给pre,当做是下一组的前驱元素。
  3. 主函数中,当前元素不断向后遍历,当栈中的数量达到k时,next指向的是cur的下一个元素,也就是后继节点。这样,前驱和后继节点就可以确定了。
  4. 那第一次的时候,前驱是null,如何将反转后的链表的首元素变为新链表的头newhead呢?在完成弹栈反转操作以后,判断newhead还是不是原链表的头head,如果还是head,说明这是第一次操作,就该把cur,也就是栈顶的这个元素赋值给newhead;如果不是head,说明不是第一次弹栈反转操作了,newhead保持原始值就可以了。
  5. 还有一个向后遍历的操作是用cur=next而不是cur=cur->next。这是因为cur是栈顶的元素,在弹栈反转的过程中cur指向的不再是下一个元素,而是上一个元素。所以会出错,使用之前保存好的next,next没有被污染,所以可以放心使用
  6. 若要将不足k个的剩余元素也反转,只需在循环以后,再次调用弹栈反转操作,将栈、上次返回的pre和本次的结尾null 即可完成要求
  7. 还有一点就是在遍历链表的过程中,有可能存在以cur为标准,那么循环中存在next的时候,next必然是null的,程序就会报错,冲出了链表的限制,一定要注意这一点

方法二

class Solution {
public:
	void revergroup(ListNode* left, ListNode* start, ListNode* end, ListNode* right) {

		ListNode* pre = start;
		ListNode* cur = start->next;
		ListNode* next = NULL;
		while (cur != right) {
			next = cur->next;
			cur->next = pre;
			pre = cur;
			cur = next;
		}
		if (left != NULL) {
			left->next = end;
		}
		start->next = right;

	}
	ListNode* reverseKGroup(ListNode* head, int k) {
		ListNode* pre = NULL;
		ListNode* start = NULL;
		ListNode* next = NULL;
		ListNode* cur = head;
		int count = 1;
		while (cur) {
			next = cur->next;
			if (count == k) {
				start = pre == NULL ? head : pre->next;
				head = pre == NULL ? cur : head;
				revergroup(pre, start, cur, next);
				pre = start;
				count = 0;
			}
			count++;
			cur = next;
		}
		return head;

	}
};

解题思路

方法二不采用额外的容器,反转链表部分没有使用栈结构,而是采用了最常用的方法,不会占用额外的空间,空间复杂度为O(1),方法1的空间复杂度为O(k)

方法二采用一个变量count记录当前数量是否到达k个元素,不断用cur向后遍历链表,若计数达到k,则继续反转链表和连接前后节点操作,若不满足计数k,则不断向后遍历,计数也不断增加

当计数达到k的时候,先确定链表的首节点,若是第一组则前驱pre应该是null,所以首节点就应该是head;若不是第一组,说明pre不为null,则链表的首节点就是pre的后继

返回的最终结果的头节点应该是第一组链表的最后一个,还是根据pre来判断是不是第一组,若pre为空说明还是第一组,那么head就应该是第一组的末节点;若pre不为null,说明不是第一组,则head保持之前的head即可。

反转链表函数完成后,将前驱pre变为上一组链表反转后的尾结点,也就是函数调用中这组链表的首节点start,再将计数清零即可

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值