[路飞]_每天刷leetcode_64(分隔链表 Split linked list in parts)

120 阅读2分钟

「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战

分隔链表 Split linked list in parts

LeetCode传送门725. 分隔链表

题目

给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。

每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。

这 k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。

返回一个由上述 k 部分组成的数组。

Given the head of a singly linked list and an integer k, split the linked list into k consecutive linked list parts.

The length of each part should be as equal as possible: no two parts should have a size differing by more than one. This may lead to some parts being null.

The parts should be in the order of occurrence in the input list, and parts occurring earlier should always have a size greater than or equal to parts occurring later.

Return an array of the k parts.

Example

Input: head = [1,2,3], k = 5
Output: [[1],[2],[3],[],[]]
Explanation:
The first element output[0] has output[0].val = 1, output[0].next = null.
The last element output[4] is null, but its string representation as a ListNode is [].

Input: head = [1,2,3,4,5,6,7,8,9,10], k = 3
Output: [[1,2,3,4],[5,6,7],[8,9,10]]
Explanation:
The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.

Constraints:

  • The number of nodes in the list is in the range [0, 1000].
  • 0 <= Node.val <= 1000
  • 1 <= k <= 50

思考线


解题思路

这道题的思路并不难,主要分为以下两步

  • 找出分隔的位置的规律
  • 把链表分割成对应的份数, 并放入数组中

这道题的难点在于我们如何设置最后返回的链表,还有如何处理前面分隔的链表可能会多出来的一节长度。由于要平均分割,所以我们要知道链表的长度。经过简单的思考,关于找出分隔的位置我们可以执行以下步骤

找出分隔的位置规律

  • 找出链表的长度
  • 把链表的长度除以分隔的份数,取整,得到每份最小的长度base = Math.floor(len/k)
  • 我们再把链表的长度对份数取余extend = len %k, 其结果extend即表示前面extend份的链表长度为base +1.

由于这个找每个链表的长度是要重复执行的,我们对当前分隔链表的长度表示为loop。解决完分隔点的问题,我们接下来要处理如何进行分隔了。

分隔链表,并放入数组

  • 首先我们创建存放结果的数组,由于要分成k份,所以我们知道数组的长度肯定是k,而且由于如果链表不够长可能导致后面数组的内容为null,为了避免讨论这种情况,我们可以在初始化数组的时候就对数组全部赋值为null
  • 我们再遍历链表,先把当前的head给对应数组的第i位,并把链表向前走loop步,并把链表进行分隔,同时把head设置为分隔后剩余链表的头部。

处理完这两步以后,我们的链表分隔也就完成了,同时也把对应的头部都放入到了数组中,我们只需要返回数组即可。

思路分析完毕,接下来贴一下我写的代码

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

function splitListToParts(head: ListNode | null, k: number): Array<ListNode | null> {
    let len = 0;
    let run = head;
    while (run) {
        run = run.next;
        len++;
    }
    const base = Math.floor(len / k)
    const extend = len % k

    const res = new Array(k).fill(null);
    let i = 0
    while (head) {
        res[i] = head;
        let loop = i  < extend ? base + 1 : base;
        console.log(loop, head, i < extend)
        while (--loop) {
            head = head.next;
        }
        if (head) {
            const next = head.next;
            head.next = null;
            head = next;
        }
        i++
    }
    return res;
};

时间复杂度

O(N): N 为链表的长度

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。