正题
725. 分隔链表
给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。
每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。
这 k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。
返回一个由上述 k 部分组成的数组。
示例 1:
输入:head = [1,2,3], k = 5
输出:[[1],[2],[3],[],[]]
解释:
第一个元素 output[0] 为 output[0].val = 1 ,output[0].next = null 。
最后一个元素 output[4] 为 null ,但它作为 ListNode 的字符串表示是 [] 。
示例 2:
输入:head = [1,2,3,4,5,6,7,8,9,10], k = 3
输出:[[1,2,3,4],[5,6,7],[8,9,10]]
解释:
输入被分成了几个连续的部分,并且每部分的长度相差不超过 1 。前面部分的长度大于等于后面部分的长度。
解析:
这是一个比较静点的关于链表的问题,要求将链表平均切割成 k 个链表,不平均的部分从 0 - k 依次补上。
求链表的长度
要求平均,就必须知道链表的长度,因为想要知道链表的长度就必须先要遍历链表,这样可能会带来一些内存和空间的消耗,也曾想过有没有办法可以不去遍历链表不去求链表长度从而平均分割,实际上都失败了,至少目前没有想到办法,所以就老老实实遍历链表,求出长度。
let length = 0
let p = head
// 求出链表长度
while(p) {
length++
p = p.next
}
// 求出每个分链表理论长度
const count = parseInt(length / k)
// 在前 more 个链表长度 中都要 + 1
const more = length % k
上述代码中,length 为理论长度,但是未必会分配均匀,所以会有一个 more 的存在,more表示前 more 个单位的链表中长度会比理论长度 +1
创建结果数组
结果数组表示返回的结果,那么结果的元素个数应该是多少呢?其实就是 K,那么我们可以有结果数组 res:
const res = new Array(parseInt(k)).fill(null)
对链表的分割
主要逻辑是将结果数组每一个元素,保证每一个元素的链表个数为理论长度。在第一个元素链表达到理论长度之后,切换到下一个元素,以此类推。因此我们需要一个 下标来记录当前结果数组的对应元素的下标,还需要记录单个链表已经加入的长度
// 定义结果数组的下标
let index = 0
// 记录 链表加入的长度
let addedLength = 0
接着我们可以重新遍历链表,完成对链表的分割
p = head
while(p) {
// 判断单个链表长度
const l = index < more ? count + 1 : count
if (addedLength === 0) {
res[index] = new ListNode(p.val, null)
cur = res[index]
}
addedLength++
if (addedLength === l) {
// 达到长度后切换下一个单链表
addedLength = 0
index++
cur.next = null
} else {
cur.next = new ListNode(p.next.val, null)
cur = cur.next
}
p = p.next
}
完整代码:
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode[]}
*/
var splitListToParts = function(head, k) {
let length = 0
let p = head
// 求出链表长度
while(p) {
length++
p = p.next
}
// 求出每个分链表理论长度
const count = parseInt(length / k)
// 在前 more 个链表长度 中都要 + 1
const more = length % k
// 创建结果数组,长度 链表长度/为理论长度
const res = new Array(parseInt(k)).fill(null)
// 重新遍历链表
p = head
// 定义结果数组的下标
let index = 0
// 记录 链表加入的长度
let addedLength = 0
let cur = null
while(p) {
// 判断单个链表长度
const l = index < more ? count + 1 : count
if (addedLength === 0) {
res[index] = new ListNode(p.val, null)
cur = res[index]
}
addedLength++
if (addedLength === l) {
// 达到长度后切换下一个单链表
addedLength = 0
index++
cur.next = null
} else {
cur.next = new ListNode(p.next.val, null)
cur = cur.next
}
p = p.next
}
return res
};