题目描述:
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
算法思想:
方法一:递归
就按示例这样,对链表调用reverseKGroup(head, 2),即以2个节点为一组反转链表,假设前两个节点已经反转,如图所示
后面的这些节点也是一条链表,而且规模(长度)比原来这条链表小,这就叫子问题。
我们可以直接递归调用reverseKGroup(head, 2),因为子问题和原问题的结构完全相同,这就是所谓的递归性质。
待子问题反转后,再把两个组连接上
伪代码可以表示为:
public ListNode reverseKGroup(ListNode head, int k) {
//反转[a,b)的链表,a到b的距离为k,表头以newHead返回
ListNode newHead = reverseList(a, b);
//递归反转以b开头,k为一组的链表
ListNode nextNode = reverseKGroup(b, k);
//组与组之间连接
a.next = nextNode;
return newHead;
那么,如何反转[a, b)之间的链表呢?
我们这里采用迭代方法,如图所示,记录当前节点以及前驱节点,在改变指针方向的时候临时记录当前节点的下一节点,改变之后同时移动前驱和当前节点
public ListNode reverseList(ListNode a, ListNode b) {
ListNode prev = null;
ListNode cur = a;
while(cur != null && cur != b){
ListNode nextTemp = cur.next;
cur.next = prev;
prev = cur;
cur = nextTemp;
}
return prev;
}
整体的代码为:
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(head == null) return null;
ListNode a = head;
ListNode b = head;
//找到下一个待反转的位置 发现子问题和原问题完全相同
for(int i = 0; i < k; i++){
if(b == null){
return head;
}
b = b.next;
}
ListNode newHead = reverseList(a, b); //k个节点反转
ListNode nextHead = reverseKGroup(b, k); //递归
a.next = nextHead;
return newHead;
}
//反转区间[a,b)的链表
public ListNode reverseList(ListNode a, ListNode b) {
ListNode prev = null;
ListNode cur = a;
while(cur != null && cur != b){
ListNode nextTemp = cur.next;
cur.next = prev;
prev = cur;
cur = nextTemp;
}
return prev;
}
}
复杂度分析:
时间复杂度:需要遍历一遍链表,故为O(n)
空间复杂度:运用到了递归,为O(n)
方法二:直接K个一组反转
其实思路和方法一也差不多,就是走K步,反转一下,再走K步,再反转一下,如果走不完K步,直接返回。
注意:我们这里引入临时节点dummy,避免讨论
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
ListNode end = pre;
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 nextNode = end.next;
end.next = null;
pre.next = reverseList(start);
start.next = nextNode;
pre = start;
end = pre;
}
return dummy.next;
}
//反转链表
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode nextNode = cur.next;
cur.next = pre;
pre = cur;
cur = nextNode;
}
return pre;
}
}
复杂度分析
时间复杂度:O(n*k)
空间复杂度:O(1)