31.K 个一组翻转链表

5 阅读2分钟

题目链接

给你链表的头节点 head ,每 k **个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k **的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

解法1 暴力解法

思路

暴力解法的思路其实和上一题一样,先把链表存在数组里,然后再进行 k 个一组的翻转,最后进行 next 指针的重置。

要注意如果后续链表长度不足 k 时应该保持原样。

代码

function reverseKGroup(head: ListNode | null, k: number): ListNode | null {
    let cur = head;
    const nodeList = [];

    while (cur) {
        nodeList.push(cur);
        cur = cur.next;
    }

    let result = [];
    let temp;
    for (let i = 0; i < nodeList.length; i += k) {
        temp = nodeList.slice(i, i + k);
        if (temp.length === k) {
            temp.reverse();
        }
        result = result.concat(temp);
    }

    for (let i = 0; i < result.length - 1; i++) {
        result[i].next = result[i + 1];
    }
    result[result.length - 1].next = null;
    return result[0];
};

时空复杂度

时间复杂度:经过了遍历,翻转以及链接操作,时间复杂度为 O(n)

空间复杂度:额外数组存储节点,O(n)

解法2 逐段翻转+链接

思路

k 个一组翻转可以看做翻转链表和链接新链表,我们把这一段直接进行翻转链表,然后这一段的头和尾的指针是不对的,没有链接到链表里去。我们再单独处理这一段就好了。

p0 的作用就是为了让翻转后的链表重新回到链表里去,初始化时是需要翻转的那一段链表的前一个节点。

代码

function reverseKGroup(head: ListNode | null, k: number): ListNode | null {
    let n = 0;
    let cur = head;
    
    while (cur) {
        n += 1;
        cur = cur.next;
    }

    const dummyHead = new ListNode(-1, head);
    let prev = null;
    let p0 = dummyHead;
    cur = head;
    while (n >= k) {
        n -= k;

        for (let i = 0; i < k; i++) {
            const next = cur.next;
            cur.next = prev;
            prev = cur;
            cur = next;
        }

        const nxt = p0.next;
        p0.next.next = cur;
        p0.next = prev;
        p0 = nxt;
    }

    return dummyHead.next;
};

时空复杂度

时间复杂度:O(n)

空间复杂度:O(1)