描述
将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表 如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样 你不能更改节点中的值,只能更改节点本身。
例如:给定的链表是 1->2->3->4->5
- 对于 k=2 , 你应该返回 2->1->4->3->5
- 对于 k=3 , 你应该返回 3->2->1->4->5
思路1:使用双端队列
将链表分段反转,空间复杂度O(n)
- 遍历将元素加入"栈"中,并计数
- 当数量达到k,将所有元素出栈,反转成新链表
- 数量重置为0
- 重复上面的步骤,直到链表为空
- 此时如果数量小于k,则将栈底的元素取出,直接接到新链表上,不需要反转
双端队列既可以当栈用,也可以当队列用,因此可以从栈顶取出元素,也可以从栈底取出
public class Solution {
public ListNode reverseKGroup (ListNode head, int k) {
ListNode ret = new ListNode(0);
ListNode cur = ret;
Deque<ListNode> deque = new LinkedList<>();
int count = 0;
while(true) {
if(head == null) {
break;
}
//入栈
deque.push(head);
head = head.next;
count++;
if(count == k) {
//反转链表:出栈
while(!deque.isEmpty()) {
cur.next = deque.pop();
cur = cur.next;
//将下一个节点置空,防止形成环
cur.next = null;
}
//重新开始计数
count = 0;
}
}
//poll为空的话会返回null,因此不需要判空
cur.next = deque.pollLast();
return ret.next;
}
}
思路2:使用三指针
整体过程和思路1类似,只是把链表反转改为了三指针,使用head和tail记录分段链表的开始和结尾。空间复杂度O(1)
这里的三指针反转有点不一样,例如:1->2->3->4->5,k=3
- 需要先反转为3->2->1->null
- 然后将新链表指向反转后的头节点,即cur->3->2->1
- 再将cur移至新链表末尾
public class Solution {
public ListNode reverseKGroup (ListNode head, int k) {
ListNode ret = new ListNode(0);
ListNode cur = ret;
ListNode tail = head;
int count = 0;
while(true) {
if(tail == null) {
break;
}
tail = tail.next;
count++;
if(count == k) {
//反转链表
ListNode pre = null;
while(head != tail) {
ListNode next = head.next;
head.next = pre;
pre = head;
head = next;
}
//新链表指向反转后的头节点
cur.next = pre;
//新链表移到最后
while(cur.next != null) {
cur = cur.next;
}
//重新开始计数
count = 0;
}
}
cur.next = head;
return ret.next;
}
}