算法
实现一个函数,输入链表头部和整数K,实现功能:
链表从后往前,每K个结点反转一下,假如头部有剩余结点,则保持不变,如
输入:1 -> 2 -> 3 -> 4 -> 5, k = 2
输出:1 -> 3 -> 2 -> 5 -> 4
与leetCode:K 个一组翻转链表类似,只不过这里的k个元素是从后往前
思路
1. 先遍历一次链表,求链表长度,复杂度O(n)
2. n % k求得开始反转的链表结点,并将当前指针cur移动到此
3. 反转cur在内的连续k个结点,整个链表被分成三部分:链表1,链表2,链表3
4. 将链表2和链表1相连,链表2和链表3相连
5. 当前指针移动一个结点,开启下一个循环,空间复杂度为O(1)
综上算法复杂度:时间O(N),空间O(1)
代码
public static void main(String[] args) throws Exception {
ListNode five = new ListNode(5, null);
ListNode four = new ListNode(4, five);
ListNode three = new ListNode(3, four);
ListNode two = new ListNode(2, three);
ListNode one = new ListNode(1, two);
JavaTest javaTest = new JavaTest();
ListNode head = javaTest.reverseKNode(one, 5);
while (head != null && head.next != null) {
System.out.print(head.val + "->");
head = head.next;
}
System.out.println(head.val);
}
static class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
private ListNode reverseKNode(ListNode head, int k) {
if (head == null || head.next == null || k <= 1) {
return head;
}
int size = countSize(head);
if (k > size) { // do nothing
return head;
}
int start = size % k; // 开始reverse的起点
ListNode dummy = new ListNode(0, head);
ListNode cur = head;
ListNode tail1 = dummy; // 将链表分成三部分:tail1表示左边链表的尾部
for (int i = 0; i < start; i++) { // 将当前指针cur移动到到坐标为start的结点
tail1 = cur;
cur = cur.next;
}
while (cur != null) {
ListNode tail2 = cur; // 将链表分成三部分:tail2表示中间链表的尾部
ListNode next = cur.next;
ListNode nextNext = (next == null) ? null : next.next;
for (int i = 1; i < k; i++) { // 反转k个连续的点
next.next = cur;
cur = next;
next = nextNext;
nextNext = (next == null) ? null : next.next;
}
tail1.next = cur; // 将链表分成三部分:cur表示中间链表的头部,将当前链表与pre链表和next表联在一起
tail1 = tail2;
tail2.next = next; // 将中间链表的尾部与右边链表的头部相连
cur = next;
}
return dummy.next;
}
private int countSize(ListNode head) {
int listLen = 0;
ListNode cur = head;
while (cur != null) {
listLen++;
cur = cur.next;
}
return listLen;
}