
思路:
1.链表分为已翻转部分 + 待翻转部分 + 未翻转部分。
2.每次翻转前,要确定翻转链表的范围,通过k次循环来确定。
3.需要记录翻转链表的前驱和后继,方便翻转完成后把已翻转和未翻转的部分连接起来。
4.初始时需要两个变量pre和end,pre表示待翻转链表的前驱,end表示待翻转链表的末尾。
5.经过k次循环,end到达末尾,记录待翻转链表的后继next = end.next。
6.翻转链表,然后将三部分链表连接起来,然后重置pre和end指针,然后进入下一次循环。
7.特殊情况:当翻转部分的长度不足k时,在定位end完成后,end == null,已经到达末尾,说明题目已经完成,直接跳出循环return即可。
复杂度分析:
1.时间复杂度:O(n*K),最好的情况为O(n),最差的情况为O(n^2)。
2.空间复杂度:O(1)。除了几个必须的节点指针外,没有占用额外空间。
附代码:
java
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode sentinel = new ListNode(0); //初始化哨兵节点
sentinel.next = head;
ListNode pre = sentinel; //pre表示当前待翻转区间的前一个节点
ListNode end = sentinel; //end表示当前待翻转区间的最后一个节点
while(end.next != null){
for(int i = 0;i < k && end != null;i++){
end = end.next; //每k个节点一组
}
if(end == null){
break; //剩余节点不足k个,直接退出
}
ListNode start = pre.next; //start表示当前组的第一个节点
ListNode next = end.next; //next表示下一组的第一个节点
end.next = null; //断开当前组与下一组的连接
//翻转当前组
pre.next = reverse(start); //pre连接到翻转后的新头
start.next = next; //当前组的第一个节点连接下一组的第一个节点,即翻转后的尾连接到下一组的头
pre = start; //pre移动到当前组的尾部
end = pre; //end同步到pre位置
}
return sentinel.next;
}
//翻转链表
private ListNode reverse(ListNode head){
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}