25. K 个一组翻转链表
题目的实际上就是一个模拟,但就如我们之前所描述的,模拟和把算法表达出来是一个意思。
要把算法表达和写出来,需要我们建模:在我们证明正确的模型下进行各种定义,然后需要保证在求解过程中要一直满足模型要求条件,于是,我们就可以把此题分为一下几步:
- 我们主函数调用旋转k个节点的函数
- 定义旋转k个节点的函数:将pre之后的k个反转,并返回k个的最后一个,如果不足k个返回null
- 得到pre之后将之后的链表分成三段链表,分成三段需要我们每段都符合单独链表的条件,即链表末尾是null:
- 1、之前段:带pre的段
- 2、当前段:pre之后的k个节点
- 3、下一段:pre之后第k+1个节点开始的那一段
- 分成三段之后,我们需要做的就是头插法,将当前段依次头插到之前段
- 最后需要处理的是将逆转的当前段的最后一个元素连接下一段的最后一个元素
- 得到pre之后将之后的链表分成三段链表,分成三段需要我们每段都符合单独链表的条件,即链表末尾是null:
当我们写题目的时候,难不难是另说,而如果我们会,需要定义好问题空间,答案空间,过程中满足的约束,这些是我们代码减少bug的根基。
public ListNode reverseKGroup(ListNode head, int k) {
ListNode pre = new ListNode(-1);
pre.next = head;
ListNode ret = pre;
while (pre != null) {
pre = reverseKNode(pre, k);
}
return ret.next;
}
/*
* 将pre之后的k个反转,并返回k个的最后一个,如果不足k个返回null
* */
public ListNode reverseKNode(ListNode pre, int k) {
if (pre == null || pre.next == null) return null;
ListNode temp = pre, ret = pre.next, next = null;
int count = 0;
while (temp != null && count < k) {
count++;
temp = temp.next;
}
if (count < k || temp == null) return null;
next = temp.next;//获取下一段的开始
temp.next = null;//清空当前段的末尾
//下面处理当前段和分裂当前段和之前段
temp = pre.next;
//把pre设置为之前段
pre.next = null;
while (temp != null) {
ListNode node = temp.next;
temp.next = pre.next;
pre.next = temp;
temp = node;
}
ret.next = next;
return ret;
}