LeetCode25 描述:给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。你不能更改节点中的值,只能更改节点本身。
方法一:
首先,因为要分组反转,我们就一组一组的处理,同时为了好处理头结点,我们新建一个虚拟头结点。为了方便循环,我们可以先遍历一遍数组,统计一下元素数量len,确定要分几组n=len/k。然后我们可以发现,对每个要反转的组,其实都可以采用,指定区间反转的思路在循环中对每个组单独进行反转。
实现代码:
public ListNode reverseKGroup (ListNode head, int k) {
// write code here
ListNode res = new ListNode(-1);
res.next = head;
ListNode cur = head;
int len = 0; //链表长度
while (cur != null) {
len++;
cur = cur.next;
}
int n = len / k; //链表分组
cur = head;
ListNode pre = res;
for (int i = 0; i < n; i++) { //要反转几组
for (int j = 0; j < k - 1; j++) { //每组反转几次
ListNode next = cur.next;
cur.next = next.next;
next.next = pre.next;
pre.next = next;
}
pre = cur; //为下一组反转作准备
cur = cur.next;
}
return res.next;
}
方法二:穿针引线法
因为要分组反转,我们可以将每个要反转的区间先拆分出来,单独反转然后再拼接回去。和前面一样,我们先建立一个虚拟节点,方便处理头节点,之后我们直接遍历,根据是否为K个找到四个关键位置,并用变量pre、start、end和next标记。
pre:要反转区间的前一个节点
start:要反转区间的开始节点。
end:要反转区间的结束节点。
next:要反转区间的下一个节点。
public ListNode reverseKGroup (ListNode head, int k) {
// write code here
ListNode res = new ListNode(-1);
res.next = head;
ListNode pre = res, end = res;
//找到要处理的区间的末尾
while (end != null) {
for (int i = 0; i < k && end != null; i++) {
end = end.next;
}
if (end == null) {
break;
}
//将要处理的区间裁剪下来
ListNode next = end.next;
ListNode start = pre.next;
end.next = null; //切断链表
reverList(start);//反转之后end变成了头节点,start变成了尾节点
//将反转的区间缝补回去
pre.next = end;
start.next = next;
pre = end = start; //为下一组的反转作准备
}
return res.next;
}
//反转链表的方法
public ListNode reverList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode next = null;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}