题目
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解答
解法一:使用双端队列 - O(k)空间
将元素放入一个双端队列里
如果放满了 k 个,就将双端队列视为栈,否则视为队列,一一弹出元素建立关系即可。
但因为使用了 O(k) 的空间, 所以这个思路效率不太行 。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(k <= 0) return head;
LinkedList<ListNode> deque = new LinkedList<>();
ListNode root = new ListNode(0);
ListNode cursor = root;
ListNode p = head;
while(p != null) {
int c = k;
while(p != null && c > 0) {
deque.offer(p);
ListNode next = p.next;
p.next = null;
p = next;
c --;
}
while(!deque.isEmpty()) {
ListNode cur = c != 0 ? deque.pollFirst() : deque.pollLast();
cursor.next = cur;
cursor = cursor.next;
}
}
return root.next;
}
}
结果
解法二:在尾部使用头插法 - O(1)空间
有点像 jdk1.7 HashMap 中的头插法。
jdk 中是以 hash表的 table[i] 作为起始点。而本题是以 k 个元素的尾部元素为起始点进行头插法而已。
要点如下:
- 声明一个虚拟头结点。
- 声明 pre 和 tail 指针,pre 指明需要倒序的 k 个元素的前驱结点,tail 指向 k 个元素的最后一个元素。
- 找到 tail 指针的位置,若剩余元素不能成 k 个,直接结束。
- 否则,先暂存新的尾节点(原来的头结点),然后对 tail 指向的尾部进行头插法,向 tail 指针后面插入元素。
- 更新 pre 和 tail 指针,不断循环,直到没有元素。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(k <= 0) return head;
ListNode root = new ListNode(0);
root.next = head;
ListNode pre = root;
ListNode tail = root;
while(tail != null) {
int c = k;
while(tail != null && c > 0) {
tail = tail.next;
c --;
}
if(tail == null) break;
ListNode head1 = pre.next;
while(pre.next != tail) {
ListNode cur = pre.next;
pre.next = cur.next;
cur.next = tail.next;
tail.next = cur;
}
pre = head1;
tail = head1;
}
return root.next;
}
}
结果
解法三:递归 - O(1)
解法二的递归版本。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode cur = head;
int c = 0;
while(cur != null && c < k) {
cur = cur.next;
c ++;
}
if(c == k) {
cur = reverseKGroup(cur, k);
while(c -- > 0) {
ListNode next = head.next;
head.next = cur;
cur = head;
head = next;
}
head = cur;
}
return head;
}
}