(牛客网刷题日记)BM3 链表中的节点每k个一组翻转

题目

将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。

数据范围: 0 ≤ n ≤ 2000 0\le n\le 2000 0n2000 1 ≤ k ≤ 2000 1\le k\le 2000 1k2000,链表中每个元素都满足 0 ≤ v a l ≤ 1000 0\le val\le 1000 0val1000
要求空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( n ) O(n) O(n)
例如:
给定的链表是 1 → 2 → 3 → 4 → 5 1\to 2\to 3\to 4\to 5 12345
对于 k = 2 k=2 k=2 , 你应该返回 2 → 1 → 4 → 3 → 5 2\to 1\to 4\to 3\to 5 21435
对于 k = 3 k=3 k=3 , 你应该返回 3 → 2 → 1 → 4 → 5 3\to 2\to 1\to 4\to 5 32145

示例1

输入:

{1,2,3,4,5},2

返回值:

{2,1,4,3,5}

示例2

输入:

{},1

返回值:

{}

解题

本题其实又是在上题BM2的基础上进一步对链表的多段进行反转,所以只要依次取出每段要反转的部分依次处理即可。
同时因为反转后链表的头节点会变,因此可以在头节点前多补一个节点,最终返回的时候返回这个新加的的节点后面一个节点即可。

ListNode head0 = new ListNode(0);
head0.next = head;

1.递归

用两个指针pointer1与pointer2,pointer1用来标记需要反转的链表前一个节点,pointer2用来向后遍历节点确保后面还有k个节点,如果没有k个节点了就直接返回,否则则对需要反转的链表部分用递归进行反转。
(牛客网刷题日记)BM3 链表中的节点每k个一组翻转_第1张图片

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode head0 = new ListNode(0);
        head0.next = head;

        ListNode pointer1 = head0;
        ListNode pointer2 = head0;
        while (true) {
            for (int i = 0; i < k; i++) {
                pointer2 = pointer2.next;
                if (pointer2 == null) {
                    return head0.next;
                }
            }
            ListNode next = pointer2.next;
            pointer2.next = null;
            recursion(pointer1.next);
            pointer1.next.next = next;
            next = pointer1.next;
            pointer1.next = pointer2;
            pointer1 = next;
            pointer2 = next;
        }
    }

    public void recursion(ListNode head) {
        if (head.next != null) {
            recursion(head.next);
            head.next.next = head;
        }
    }
}

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

2.迭代

先用pointer1存下需要反转的链表部分前一个节点,再用pointer2向后走k位来判断是否还有k位节点用于反转,如果有则按顺序依次将相邻的两个节点间顺序调转即可
(牛客网刷题日记)BM3 链表中的节点每k个一组翻转_第2张图片

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode head0 = new ListNode(0);
        head0.next = head;

        ListNode pointer1 = head0;
        while (true) {
            ListNode pointer2 = pointer1;
            for (int i = 0; i < k; i++) {
                pointer2 = pointer2.next;
                if (pointer2 == null) {
                    return head0.next;
                }
            }
            ListNode node1 = pointer1.next;
            ListNode node = node1;
            ListNode node2 = pointer1.next.next;
            for (int i = 1; i < k; i++) {
                ListNode node3 = node2.next;
                node2.next = node1;
                node1 = node2;
                node2 = node3;
            }
            pointer1.next = node1;
            pointer1 = node;
            node.next = node2;
        }
    }
}

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

3.栈

先用pointer1存下需要反转的链表部分前一个节点,再用pointer2向后走k位边将各节点放入栈中便判断是否还有k位节点用于反转,如果有则通过栈的先入后出将存入栈的节点一一取出接到pointer1后面,在与后段的链表相连,依次类推一一反转
(牛客网刷题日记)BM3 链表中的节点每k个一组翻转_第3张图片

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode head0 = new ListNode(0);
        head0.next = head;
        ListNode pointer1 = head0;
        while (true) {
            ListNode pointer2 = pointer1;
            Deque<ListNode> deque = new LinkedList<>();
            for (int i = 0; i < k; i++) {
                pointer2 = pointer2.next;
                deque.offerLast(pointer2);
                if (pointer2 == null) {
                    return head0.next;
                }
            }
            pointer2 = pointer2.next;
            while (!deque.isEmpty()) {
                pointer1.next = deque.pollLast();
                pointer1 = pointer1.next;
            }
            pointer1.next = pointer2;
        }
    }
}

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

你可能感兴趣的:(牛客网刷题日记,算法,java,笔记,链表)