leetcode25.K个一组翻转链表
Question
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
你的算法只能使用常数的额外空间。 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
Answer
解法一
public class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
//开始时pre和end都在dummyNode处
ListNode pre = dummyNode; //待翻转链表的前驱
ListNode end = dummyNode; //待翻转链表的末尾
while(end.next != null) {
for(int i = 0; i < k && end != null; i++) {
end = end.next; //end指针后移,看是否足够翻转
}
if(end == null) break; //不够k个就跳出
ListNode start = pre.next;
ListNode next = end.next; //next记录待翻转的结点
end.next = null; //从end往后断开,准备翻转【start,end】区间
pre.next = reverse(start); //更新pre
start.next = next; //将翻转后的部分与后面未翻转部分连起来
pre = start; //重置pre指针
end = pre; //重置end指针
}
return dummyNode.next;
}
private ListNode reverse(ListNode head) {
//单链表的翻转操作,遍历实现
ListNode pre = null;
ListNode curr = head;
ListNode temp = null;
while(curr != null) {
temp = curr.next;
curr.next = pre;
pre = curr;
curr = temp;
}
return pre;
}
}
解法二
import java.util.ArrayDeque;
import java.util.Deque;
public class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
Deque<ListNode> stack = new ArrayDeque<ListNode>();
ListNode dummyNode = new ListNode(0);
ListNode p = dummyNode; //p用于生成新的链表,dummyNode记住头结点
while(true) {
int count = 0;
ListNode tmp = head; //临时结点tmp
while(tmp != null && count < k) {
stack.add(tmp); //往栈里头加
tmp = tmp.next;
count++;
}
if(count != k) {
//不够k个不翻转
p.next = head;
break;
}
while(!stack.isEmpty()) {
p.next = stack.pollLast(); //取出来
p = p.next;
}
p.next = tmp;
head = tmp;
}
return dummyNode.next;
}
}
Attention
解法一(常数空间):
题解转载自王小二
- 链表分区为已翻转部分+待翻转部分+未翻转部分
- 每次翻转前,要确定翻转链表的范围,这个必须通过 k 次循环来确定
- 需记录翻转链表前驱和后继,方便翻转完成后把已翻转部分和未翻转部分连接起来
- 初始需要两个变量 pre 和 end,pre 代表待翻转链表的前驱,end 代表待翻转链表的末尾
- 经过k此循环,end 到达末尾,记录待翻转链表的后继 next = end.next
- 翻转链表,然后将三部分链表连接起来,然后重置 pre 和 end 指针,然后进入下一次循环
- 特殊情况,当翻转部分长度不足 k 时,在定位 end 完成后,end==null,已经到达末尾,说明题目已完成,直接返回即可
- 时间复杂度为 O(n*K) ,最好的情况为 O(n) ,最差的情况未 O(n^2)
- 空间复杂度为 O(1) ,除了几个必须的节点指针外,我们并没有占用其他空间