K个一组反转
主要有两种思路:
- 穿针引线法实现分组反转,及直接反转
- 头插法实现分组反转,及定义一个虚拟头节点,去分组反转,切换每个组的时候,将头节点也换到对应的每组的上一个节点
穿针引线法
public static ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
ListNode end = dummy;
while (end.next != null) {
for (int i = 0; i < k && end != null; i++) {
end = end.next;
}
if (end == null)
break;
ListNode start = pre.next;
ListNode next = end.next;
end.next = null;
pre.next = reverse(start);
start.next = next;
pre = start;
end = pre;
}
return dummy.next;
}
private static ListNode reverse(ListNode head) {
ListNode pre = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = pre;
pre = curr;
curr = next;
}
return pre;
}
头插法
直接上代码,细节已经写在代码注释上,建议读者边画图,边读代码,方便理解:
public static ListNode reverseKGroup2(ListNode head, int k) {
//定义虚拟头结点
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode cur = head;
int len = 0;
//先计算出链表的长度
while(cur != null) {
len++;
cur = cur.next;
}
//计算出有n组
int n = len/k;
ListNode pre = dummyNode;
cur = head;
//第一层遍历组
for(int i=0;i<n;i++) {
//第二层遍历每个组中的节点并反转
for(int j=0;j<k-1;j++) {
//先记录当前节点的下一个节点next
ListNode next = cur.next;
//当cur的next指针指向cur的下下个节点,防止节点丢失,不能够继续反转
cur.next = cur.next.next;
//将next节点的 指针指向pre的下一个
next.next = pre.next;
//pre的next指针指向next
pre.next = next;
}
//分组内的链表反转完后,将pre指针指向下一组的前一个节点
pre = cur;
//cur指针向前移动一位
cur = cur.next;
}
return dummyNode.next;
}