模拟法:分段+反转
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dum = new ListNode(0);//构造虚拟节点,跟踪头节点
dum.next = head;//指向最初的头节点
ListNode prev = dum;//作为prev节点记录,方便对接后段反转后的子链表
while (head!=null){//【段头】指针
ListNode tail = prev;//【段尾】指针
for (int i = 0; i < k; i++) {
tail = tail.next;//移动
if (tail==null) return dum.next;//段尾节点为空说明当前长度不够,不用再反转
}
ListNode[] nodes = reverse(head,tail);//分段反转
head = nodes[1];//因反转,需纠正段首和段尾的指针位置
tail = nodes[0];//同上
prev.next = head;//链接上一端链表的节点
//1:↑,注意,第一段的链表反转后,因dum和prev同一引用,所以prev指向新的头节点时dum也会生效:dum.next更新
prev = tail;//移动prev,为下一分段准备
//2:↑,注意:执行完这句后prev就和hair不再是同一个引用了,后续分段的反转则不会再对dum.next有影响
head = prev.next;//移动head,为下一分段准备
}
return dum.next;
}
public ListNode[] reverse(ListNode head, ListNode tail) {
//↑:1(head)-2(tail)-3-4-5 或 2-1-3(head)-4(tail)-5
ListNode dum = tail.next;
//↑:tail.next作为最后节点,即能完成head-tail的反转,也能方便连接下一分段的链表
ListNode cur = head;
while (dum!=tail){
//↑:不用cur!=tail.next,tail会被改变指向导致进入死循环
ListNode next = cur.next;
cur.next = dum;
dum = cur;
cur = next;
}
//↑:2(tail)-1(head)-3-4-5 或 2-1-4(head)-3(tail)-5
return new ListNode[]{head,tail};
//↑:返回两个指针,方便外面交换
}