描述 合并K分类列表 状态:
您有一系列
k
链接-列表lists
,每个链接-列表按升序排序。合并所有链接-列表为一个排序的链接-列出并返回。
例如:
Input: lists = [[1, 4, 5], [1, 3, 4], [2, 6]]
Output: [1, 1, 2, 3, 4, 4, 5, 6]
Explanation: The linked-lists are:
[1->4->5,1->3->4,2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6
起初这个问题有点让我感到困惑,但是 NEETCODE 很有意义。
解决方案的方法是 合并排序算法 ,这是您从任何介绍性计算机科学课程中可能记得的最熟悉的算法之一。
现在,当我们将数组作为输入作为输入时,我们通常会合并排序,我们将数组递归将数组分为左和右半,并继续合并它们,直到整个数组对整个数组进行排序。这是我们熟悉的朋友在JavaScript中的样子:
function mergeSort(arr) {if (arr.length <= 1) {return arr;}let left = arr.slice(0, Math.floor(arr.length / 2));let right = arr.slice(Math.floor(arr.length / 2), arr.length);mergeSort(left);mergeSort(right);merge(left, right, arr);return arr;
}function merge(left, right, arr) {let index = 0;while (left.length && right.length) {if (left[0] < right[0]) {arr[index++] = left.shift();} else {arr[index++] = right.shift();}}while (left.length) {arr[index++] = left.shift();}while (right.length) {arr[index++] = right.shift();}
}
但是,我们要使用的是 * merge
功能。
由于我们还使用链接列表,因此看起来会有所不同。使用TypeScript,看起来像这样:
function merge(list1: ListNode | null, list2: ListNode | null) {let result = new ListNode(0);let currentNode = result;while (list1 !== null && list2 !== null) {if (list1.val < list2.val) {currentNode.next = list1;list1 = list1.next;} else {currentNode.next = list2;list2 = list2.next;}currentNode = currentNode.next;}if (list1 !== null) {currentNode.next = list1;}if (list2 !== null) {currentNode.next = list2;}return result.next;
}
自从我们给予 k
排序列表,我们将合并列表对,并继续合并 lists
大于1:
function mergeKLists(lists: Array<ListNode | null>): ListNode | null {if (lists === null || lists.length === 0) {return null;}while (lists.length > 1) {let mergedLists = [];for (let i = 0; i < lists.length; i += 2) {let list1 = lists[i];let list2 = i + 1 < lists.length ? lists[i + 1] : null;mergedLists.push(merge(list1, list2));}lists = mergedLists;} return lists[0];
};
笔记 |
---|
如果 list2 是 null (在长度的情况下 lists 甚至不是),合并 list1 和 list2 将是 list1 。 |
总体而言,解决方案看起来像这样:
/*** 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 mergeKLists(lists: Array<ListNode | null>): ListNode | null {if (lists === null || lists.length === 0) {return null;}while (lists.length > 1) {let mergedLists = [];for (let i = 0; i < lists.length; i += 2) {let list1 = lists[i];let list2 = i + 1 < lists.length ? lists[i + 1] : null;mergedLists.push(merge(list1, list2));}lists = mergedLists;} return lists[0];
};function merge(list1: ListNode | null, list2: ListNode | null) {let result = new ListNode(0);let currentNode = result;while (list1 !== null && list2 !== null) {if (list1.val < list2.val) {currentNode.next = list1;list1 = list1.next;} else {currentNode.next = list2;list2 = list2.next;}currentNode = currentNode.next;}if (list1 !== null) {currentNode.next = list1;}if (list2 !== null) {currentNode.next = list2;}return result.next;
}
时间和空间复杂性
时间复杂性是o(n log k)o(n\ log\ k) - 也看 NEETCODE的解释 - ,如果您记得合并排序功能的时间复杂性是o(n log n)o(n\ 日志\ n) :我们通过合并操作中的每个项目,但是由于每次输入都会减半,我们会记录NLOG\ n次。在这里类似,nn是指节点的数量,而kk是列表的数量。
空间复杂性是O(k)o(k) 当我们保留临时的时,kk是列表的数量 mergedLists
多变的。