用100道题拿下你的算法面试(链表篇-4):合并 K 个有序链表

一、面试问题

给定 k 个长度各不相同的有序链表 ,需要将它们合并为单个有序链表,并保持原有升序顺序。

示例 1:

输入:

输出:

解释:合并后的链表保持升序排列,每个元素都大于前一个元素。

示例 2:

输入:

输出:

二、[朴素解法-1] 依次逐个合并链表 ------ 时间复杂度 :O (N × k2)),空间复杂度:O(1)

(一) 解法思路

思路:先初始化结果链表为空。然后利用合并两个有序链表的思想,将每条链表逐一合并到结果链表中。始终把结果链表当作第一个链表,把待合并的链表当作第二个链表,最终返回合并后的结果链表。

(二) 使用 6 种语言实现

1. C++

cpp 复制代码
#include <iostream>
#include<vector>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node(int x) {
        data = x;
        next = nullptr;
    }
};

// 合并两个链表的函数
Node* mergeTwo(Node* head1, Node* head2) {
    
    // 创建一个哑节点以简化合并过程
    Node* dummy = new Node(-1);
    Node* curr = dummy;

    // 遍历两个链表
    while (head1 != nullptr && head2 != nullptr) {
      
        // 将较小的节点加入合并后的链表
        if (head1->data <= head2->data) {
            curr->next = head1;
            head1 = head1->next;
        } else {
            curr->next = head2;
            head2 = head2->next;
        }
        curr = curr->next;
    }

    // 如果还有剩余链表,直接拼接在合并链表的末尾
    if (head1 != nullptr) {
        curr->next = head1;
    } else {
        curr->next = head2;
    }

    // 返回从哑节点的下一个节点开始的合并链表
    return dummy->next;
}

// 合并 K 个有序链表的函数
Node* mergeKLists(vector<Node*>& arr) {
  
    // 初始化结果为空
    Node *res = nullptr;
    
    // 将所有链表依次与 res 合并,并持续更新 res
    for (Node *node : arr) 
        res = mergeTwo(res, node);
        
    return res;
}

void printList(Node* node) {
    while (node != nullptr) {
        cout << node->data;
        if(node->next)
        cout<<" -> ";
        node = node->next;
    }
}

int main() {
    int k = 3; 
  
    vector<Node*> arr(k);

    arr[0] = new Node(1);
    arr[0]->next = new Node(3);
    arr[0]->next->next = new Node(5);
    arr[0]->next->next->next = new Node(7);

    arr[1] = new Node(2);
    arr[1]->next = new Node(4);
    arr[1]->next->next = new Node(6);
    arr[1]->next->next->next = new Node(8);

    arr[2] = new Node(0);
    arr[2]->next = new Node(9);
    arr[2]->next->next = new Node(10);
    arr[2]->next->next->next = new Node(11);
    
    Node* head = mergeKLists(arr);

    printList(head);

    return 0;
}

2. C

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node* next;
};

struct Node* createNode(int data);

// 合并两个链表的函数
struct Node* mergeTwo(struct Node* head1, struct Node* head2) {
    
    // 创建一个哑节点以简化合并过程
    struct Node* dummy = createNode(-1);
    struct Node* curr = dummy;

    // 遍历两个链表
    while (head1 != NULL && head2 != NULL) {
      
        // 将较小的节点加入合并后的链表
        if (head1->data <= head2->data) {
            curr->next = head1;
            head1 = head1->next;
        } else {
            curr->next = head2;
            head2 = head2->next;
        }
        curr = curr->next;
    }

    // 如果还有剩余链表,直接拼接在合并链表的末尾
    if (head1 != NULL) {
        curr->next = head1;
    } else {
        curr->next = head2;
    }

    // 返回从哑节点的下一个节点开始的合并链表
    struct Node* merged = dummy->next;
    free(dummy);
    return merged;
}

// 合并 K 个有序链表的函数
struct Node* mergeKLists(struct Node** arr, int k) {
  
    // 初始化结果为空
    struct Node* res = NULL;
    
    // 将所有链表依次与 res 合并,并持续更新 res
    for (int i = 0; i < k; i++) 
        res = mergeTwo(res, arr[i]);
        
    return res;
}

void printList(struct Node* node) {
    while (node != NULL) {
        printf("%d", node->data);
        if(node->next)
        printf(" -> ");
        node = node->next;
    }
}

struct Node* createNode(int data) {
    struct Node* newNode = 
    (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

int main() {
    int k = 3; 
    struct Node* arr[k];

    arr[0] = createNode(1);
    arr[0]->next = createNode(3);
    arr[0]->next->next = createNode(5);
    arr[0]->next->next->next = createNode(7);

    arr[1] = createNode(2);
    arr[1]->next = createNode(4);
    arr[1]->next->next = createNode(6);
    arr[1]->next->next->next = createNode(8);

    arr[2] = createNode(0);
    arr[2]->next = createNode(9);
    arr[2]->next->next = createNode(10);
    arr[2]->next->next->next = createNode(11);
    
    struct Node* head = mergeKLists(arr, k);

    printList(head);

    return 0;
}

3. Java

java 复制代码
import java.util.List;
import java.util.ArrayList;

class Node {
    int data;
    Node next;

    Node(int x) {
        data = x;
        next = null;
    }
}

class DSA {
    
    // 合并两个链表的函数
    static Node mergeTwo(Node head1, Node head2) {
        
        // 创建一个哑节点以简化合并过程
        Node dummy = new Node(-1);
        Node curr = dummy;

        // 遍历两个链表
        while (head1 != null && head2 != null) {
          
            // 将较小的节点加入合并后的链表
            if (head1.data <= head2.data) {
                curr.next = head1;
                head1 = head1.next;
            } else {
                curr.next = head2;
                head2 = head2.next;
            }
            curr = curr.next;
        }

        // 如果还有剩余链表,直接拼接在合并链表的末尾
        if (head1 != null) {
            curr.next = head1;
        } else {
            curr.next = head2;
        }

        // 返回从哑节点的下一个节点开始的合并链表
        return dummy.next;
    }

    // 合并 K 个有序链表的函数
    static Node mergeKLists(List<Node> arr) {
      
        // 初始化结果为空
        Node res = null;
        
        // 将所有链表依次与 res 合并,并持续更新 res
        for (Node node : arr) 
            res = mergeTwo(res, node);
            
        return res;
    }

    static void printList(Node node) {
        while (node != null) {
            System.out.print(node.data);
            if(node.next!=null)
            System.out.print(" -> ");
            node = node.next;
        }
    }

    public static void main(String[] args) {
        List<Node> arr = new ArrayList<>();

        arr.add(new Node(1));
        arr.get(0).next = new Node(3);
        arr.get(0).next.next = new Node(5);
        arr.get(0).next.next.next = new Node(7);

        arr.add(new Node(2));
        arr.get(1).next = new Node(4);
        arr.get(1).next.next = new Node(6);
        arr.get(1).next.next.next = new Node(8);

        arr.add(new Node(0));
        arr.get(2).next = new Node(9);
        arr.get(2).next.next = new Node(10);
        arr.get(2).next.next.next = new Node(11);

        Node head = mergeKLists(arr);

        printList(head);
    }
}

4. Python

python 复制代码
class Node:
    def __init__(self, x):
        self.data = x
        self.next = None

# 合并两个链表的函数
def mergeTwo(head1, head2):
    
    # 创建一个哑节点以简化合并过程
    dummy = Node(-1)
    curr = dummy

    # 遍历两个链表
    while head1 is not None and head2 is not None:
      
        # 将较小的节点加入合并后的链表
        if head1.data <= head2.data:
            curr.next = head1
            head1 = head1.next
        else:
            curr.next = head2
            head2 = head2.next
        curr = curr.next

    # 如果还有剩余链表,直接拼接在合并链表的末尾
    if head1 is not None:
        curr.next = head1
    else:
        curr.next = head2

    # 返回从哑节点的下一个节点开始的合并链表
    return dummy.next

# 合并 K 个有序链表的函数
def mergeKLists(arr):
    
    # 初始化结果为空
    res = None
    
    # 将所有链表依次与 res 合并,并持续更新 res
    for node in arr:
        res = mergeTwo(res, node)
        
    return res

def printList(node):
    while node is not None:
        print(f"{node.data}", end="")
        if node.next is not None:
            print(" -> ", end="")
        node = node.next
    print()

if __name__ == "__main__":
    arr = []

    node1 = Node(1)
    node1.next = Node(3)
    node1.next.next = Node(5)
    node1.next.next.next = Node(7)
    arr.append(node1)

    node2 = Node(2)
    node2.next = Node(4)
    node2.next.next = Node(6)
    node2.next.next.next = Node(8)
    arr.append(node2)

    node3 = Node(0)
    node3.next = Node(9)
    node3.next.next = Node(10)
    node3.next.next.next = Node(11)
    arr.append(node3)

    head = mergeKLists(arr)
    printList(head)

5. C#

cs 复制代码
using System;
using System.Collections.Generic;

class Node {
    public int data;
    public Node next;

    public Node(int x) {
        data = x;
        next = null;
    }
}

class DSA {
    static Node mergeTwo(Node head1, Node head2) {
        
        // 创建一个哑节点以简化合并过程
        Node dummy = new Node(-1);
        Node curr = dummy;

        // 遍历两个链表
        while (head1 != null && head2 != null) {
          
            // 将较小的节点加入合并后的链表
            if (head1.data <= head2.data) {
                curr.next = head1;
                head1 = head1.next;
            } else {
                curr.next = head2;
                head2 = head2.next;
            }
            curr = curr.next;
        }

        // 如果还有剩余链表,直接拼接在合并链表的末尾
        if (head1 != null) {
            curr.next = head1;
        } else {
            curr.next = head2;
        }

        // 返回从哑节点的下一个节点开始的合并链表
        return dummy.next;
    }

    static Node mergeKLists(List<Node> arr) {
        
        // 初始化结果为空
        Node res = null;
        
        // 将所有链表依次与 res 合并,并持续更新 res
        foreach (Node node in arr)
            res = mergeTwo(res, node);
            
        return res;
    }

   static void printList(Node head) {
        Node temp = head;
        while (temp != null) {
            Console.Write(temp.data + "");
            if(temp.next!=null)
            Console.Write(" -> ");
            temp = temp.next;
        }
        Console.WriteLine();
    } 

    static void Main(string[] args) {
        List<Node> arr = new List<Node>();

        Node node1 = new Node(1);
        node1.next = new Node(3);
        node1.next.next = new Node(5);
        node1.next.next.next = new Node(7);
        arr.Add(node1);

        Node node2 = new Node(2);
        node2.next = new Node(4);
        node2.next.next = new Node(6);
        node2.next.next.next = new Node(8);
        arr.Add(node2);

        Node node3 = new Node(0);
        node3.next = new Node(9);
        node3.next.next = new Node(10);
        node3.next.next.next = new Node(11);
        arr.Add(node3);

        Node head = mergeKLists(arr);
        printList(head);
    }
}

6. JavaScript

javascript 复制代码
class Node {
    constructor(x) {
        this.data = x;
        this.next = null;
    }
}

// 合并两个链表的函数
function mergeTwo(head1, head2) {
    
    // 创建一个哑节点以简化合并过程
    let dummy = new Node(-1);
    let curr = dummy;

    // 遍历两个链表
    while (head1 !== null && head2 !== null) {
      
        // 将较小的节点加入合并后的链表
        if (head1.data <= head2.data) {
            curr.next = head1;
            head1 = head1.next;
        } else {
            curr.next = head2;
            head2 = head2.next;
        }
        curr = curr.next;
    }

    // 如果还有剩余链表,直接拼接在合并链表的末尾
    if (head1 !== null) {
        curr.next = head1;
    } else {
        curr.next = head2;
    }

    // 返回从哑节点的下一个节点开始的合并链表
    return dummy.next;
}

// 合并 K 个有序链表的函数
function mergeKLists(arr) {
    
    // 初始化结果为空
    let res = null;
    
    // 将所有链表依次与 res 合并,并持续更新 res
    for (let node of arr) 
        res = mergeTwo(res, node);
        
    return res;
}

function printList(node) {
    while (node !== null) {
        console.log(node.data + " ");
        node = node.next;
    }
}
// 测试代码
let arr = [];

let node1 = new Node(1);
node1.next = new Node(3);
node1.next.next = new Node(5);
node1.next.next.next = new Node(7);
arr.push(node1);

let node2 = new Node(2);
node2.next = new Node(4);
node2.next.next = new Node(6);
node2.next.next.next = new Node(8);
arr.push(node2);

let node3 = new Node(0);
node3.next = new Node(9);
node3.next.next = new Node(10);
node3.next.next.next = new Node(11);
arr.push(node3);

let head = mergeKLists(arr);
printList(head);

(三) 代码输出和算法复杂度

输出:

复制代码
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11

时间复杂度:O (n×k²)。为简化分析,我们假设每条链表的长度都为 n。在最坏情况下,总耗时为 n + 2n + 3n + ... + k×n。该数列的和为 n×k×(k+1)/2,时间复杂度为 O (n×k²)。

空间复杂度:O(1)。

三、【朴素解法-2】重复选取最小节点 ------ 时间复杂度 O(n * k2),空间复杂度 O (1)

(一) 解法思路

该方法的思路是:遍历全部 k 个链表的头节点,将值最小的头节点添加到结果链表中,然后将该链表的头指针后移一位。重复此过程,直到所有节点都被处理完毕。

分步实现思路:

  1. 为结果链表初始化一个哑节点头。
  2. 在全部 k 个链表中找到值最小的节点。
  3. 将找到最小节点的那个链表的当前指针后移一位。
  4. 把这个值最小的节点添加到结果链表的末尾。
  5. 重复上述步骤,直到所有节点都被处理完毕。

(二) 使用 5 种语言实现

1. C++

cpp 复制代码
#include <iostream>
#include<vector>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node(int x) {
        data = x;
        next = nullptr;
    }
};

// 获取值最小的节点的函数
Node* getMinNode(vector<Node*> &arr) {
    
    Node* mini = nullptr;
    int index = -1;
    
    for (int i=0; i<arr.size(); i++) {
        
        // 如果当前链表已处理完毕
        if (arr[i]==nullptr) continue;
        
        // 如果最小节点未设置,或当前头节点值更小
        if (mini==nullptr || arr[i]->data<mini->data) {
            index = i;
            mini = arr[i];
        }
    }
    
    // 将对应链表的头节点后移一位
    if (index!=-1) arr[index] = arr[index]->next;
    
    return mini;
}

// 合并 K 个有序链表的函数
Node* mergeKLists(vector<Node*>& arr) {
  
    // 创建一个哑节点以简化合并过程
    Node* dummy = new Node(-1);
    Node* tail = dummy;
    
    Node* mini = getMinNode(arr);
    
    // 处理所有节点
    while (mini != nullptr) {
        
        // 将最小节点添加到结果链表
        tail->next = mini;
        tail = mini;
        
        // 查找下一个最小节点
        mini = getMinNode(arr);
    }

    // 返回从哑节点的下一个节点开始的合并链表
    return dummy->next;
}

void printList(Node* node) {
    while (node != nullptr) {
        cout << node->data;
        if(node->next)
        cout<<" -> ";
        node = node->next;
    }
}

int main() {
    int k = 3; 
  
    vector<Node*> arr(k);

    arr[0] = new Node(1);
    arr[0]->next = new Node(3);
    arr[0]->next->next = new Node(5);
    arr[0]->next->next->next = new Node(7);

    arr[1] = new Node(2);
    arr[1]->next = new Node(4);
    arr[1]->next->next = new Node(6);
    arr[1]->next->next->next = new Node(8);

    arr[2] = new Node(0);
    arr[2]->next = new Node(9);
    arr[2]->next->next = new Node(10);
    arr[2]->next->next->next = new Node(11);
    
    Node* head = mergeKLists(arr);

    printList(head);

    return 0;
}

2. Java

java 复制代码
import java.util.List;
import java.util.ArrayList;

class Node {
    int data;
    Node next;

    Node(int x) {
        data = x;
        next = null;
    }
}

class DSA {
    
    // 获取值最小的节点的函数
    static Node getMinNode(List<Node> arr) {
        Node mini = null;
        int index = -1;
        
        for (int i = 0; i < arr.size(); i++) {
            
            // 如果当前链表已处理完毕
            if (arr.get(i) == null) continue;
            
            // 如果最小节点未设置,或当前头节点值更小
            if (mini == null || arr.get(i).data < mini.data) {
                index = i;
                mini = arr.get(i);
            }
        }
        
        // 将对应链表的头节点后移一位
        if (index != -1) arr.set(index, arr.get(index).next);
        
        return mini;
    }
    
    // 合并 K 个有序链表的函数
    static Node mergeKLists(List<Node> arr) {
        // 创建一个哑节点以简化合并过程
        Node dummy = new Node(-1);
        Node tail = dummy;
    
        Node mini = getMinNode(arr);
        
        // 处理所有节点
        while (mini != null) {
            
            // 将最小节点添加到结果链表
            tail.next = mini;
            tail = mini;
            
            // 查找下一个最小节点
            mini = getMinNode(arr);
        }
    
        // 返回从哑节点的下一个节点开始的合并链表
        return dummy.next;
    }
    
    static void printList(Node node) {
        while (node != null) {
            System.out.print(node.data);
            if(node.next!=null)
            {
                System.out.print(" -> ");
            }
            node = node.next;
        }
    }
    
    public static void main(String[] args) {
        List<Node> arr = new ArrayList<>();
        arr.add(new Node(1));
        arr.get(0).next = new Node(3);
        arr.get(0).next.next = new Node(5);
        arr.get(0).next.next.next = new Node(7);
    
        arr.add(new Node(2));
        arr.get(1).next = new Node(4);
        arr.get(1).next.next = new Node(6);
        arr.get(1).next.next.next = new Node(8);
    
        arr.add(new Node(0));
        arr.get(2).next = new Node(9);
        arr.get(2).next.next = new Node(10);
        arr.get(2).next.next.next = new Node(11);
    
        Node head = mergeKLists(arr);
        printList(head);
    }
}

3. Python

python 复制代码
class Node:
    def __init__(self, x):
        self.data = x
        self.next = None

# 获取值最小的节点的函数
def getMinNode(arr):
    mini = None
    index = -1

    for i in range(len(arr)):
      
        # 如果当前链表已处理完毕
        if arr[i] is None:
            continue

        # 如果最小节点未设置,或当前头节点值更小
        if mini is None or arr[i].data < mini.data:
            index = i
            mini = arr[i]

    # 将对应链表的头节点后移一位
    if index != -1:
        arr[index] = arr[index].next

    return mini

# 合并 K 个有序链表的函数
def mergeKLists(arr):
    # 创建一个哑节点以简化合并过程
    dummy = Node(-1)
    tail = dummy

    mini = getMinNode(arr)

    # 处理所有节点
    while mini:
        
        # 将最小节点添加到结果链表
        tail.next = mini
        tail = mini

        # 查找下一个最小节点
        mini = getMinNode(arr)

    # 返回从哑节点的下一个节点开始的合并链表
    return dummy.next

def printList(node):
    while node is not None:
        print(f"{node.data}", end="")
        if node.next is not None:
            print(" -> ", end="")
        node = node.next
    print()

if __name__ == "__main__":
    arr = [None] * 3

    arr[0] = Node(1)
    arr[0].next = Node(3)
    arr[0].next.next = Node(5)
    arr[0].next.next.next = Node(7)

    arr[1] = Node(2)
    arr[1].next = Node(4)
    arr[1].next.next = Node(6)
    arr[1].next.next.next = Node(8)

    arr[2] = Node(0)
    arr[2].next = Node(9)
    arr[2].next.next = Node(10)
    arr[2].next.next.next = Node(11)

    head = mergeKLists(arr)
    printList(head)

4. C#

cs 复制代码
using System;
using System.Collections.Generic;

class Node {
    public int data;
    public Node next;

    public Node(int x) {
        data = x;
        next = null;
    }
}

class DSA {
    
    // 获取值最小的节点的函数
    static Node getMinNode(List<Node> arr) {
        Node mini = null;
        int index = -1;

        for (int i = 0; i < arr.Count; i++) {
            // 如果当前链表已处理完毕
            if (arr[i] == null) continue;

            // 如果最小节点未设置,或当前头节点值更小
            if (mini == null || arr[i].data < mini.data) {
                index = i;
                mini = arr[i];
            }
        }

        // 将对应链表的头节点后移一位
        if (index != -1) arr[index] = arr[index].next;

        return mini;
    }

    // 合并 K 个有序链表的函数
    static Node mergeKLists(List<Node> arr) {
        // 创建一个哑节点以简化合并过程
        Node dummy = new Node(-1);
        Node tail = dummy;

        Node mini = getMinNode(arr);

        // 处理所有节点
        while (mini != null) {
            
            // 将最小节点添加到结果链表
            tail.next = mini;
            tail = mini;

            // 查找下一个最小节点
            mini = getMinNode(arr);
        }

        // 返回从哑节点的下一个节点开始的合并链表
        return dummy.next;
    }

    static void printList(Node head) {
        Node temp = head;
        while (temp != null) {
            Console.Write(temp.data + "");
            if(temp.next!=null)
            Console.Write(" -> ");
            temp = temp.next;
        }
        Console.WriteLine();
    }

    static void Main() {
        List<Node> arr = new List<Node>();

        arr.Add(new Node(1));
        arr[0].next = new Node(3);
        arr[0].next.next = new Node(5);
        arr[0].next.next.next = new Node(7);

        arr.Add(new Node(2));
        arr[1].next = new Node(4);
        arr[1].next.next = new Node(6);
        arr[1].next.next.next = new Node(8);

        arr.Add(new Node(0));
        arr[2].next = new Node(9);
        arr[2].next.next = new Node(10);
        arr[2].next.next.next = new Node(11);

        Node head = mergeKLists(arr);
        printList(head);
    }
}

5. JavaScript

javascript 复制代码
class Node {
    constructor(x) {
        this.data = x;
        this.next = null;
    }
}

// 获取值最小的节点的函数
function getMinNode(arr) {
    let mini = null;
    let index = -1;

    for (let i = 0; i < arr.length; i++) {
        
        // 如果当前链表已处理完毕
        if (arr[i] === null) continue;

        // 如果最小节点未设置,或当前头节点值更小
        if (mini === null || arr[i].data < mini.data) {
            index = i;
            mini = arr[i];
        }
    }

    // 将对应链表的头节点后移一位
    if (index !== -1) arr[index] = arr[index].next;

    return mini;
}

// 合并 K 个有序链表的函数
function mergeKLists(arr) {
    // 创建一个哑节点以简化合并过程
    let dummy = new Node(-1);
    let tail = dummy;

    let mini = getMinNode(arr);

    // 处理所有节点
    while (mini !== null) {
        
        // 将最小节点添加到结果链表
        tail.next = mini;
        tail = mini;

        // 查找下一个最小节点
        mini = getMinNode(arr);
    }

    // 返回从哑节点的下一个节点开始的合并链表
    return dummy.next;
}

function printList(node) {
    while (node !== null) {
        process.stdout.write(node.data.toString());
        if (node.next !== null) {
            process.stdout.write(" -> ");
        }
        node = node.next;
    }
}

let arr = [];

arr.push(new Node(1));
arr[0].next = new Node(3);
arr[0].next.next = new Node(5);
arr[0].next.next.next = new Node(7);

arr.push(new Node(2));
arr[1].next = new Node(4);
arr[1].next.next = new Node(6);
arr[1].next.next.next = new Node(8);

arr.push(new Node(0));
arr[2].next = new Node(9);
arr[2].next.next = new Node(10);
arr[2].next.next.next = new Node(11);

let head = mergeKLists(arr);
printList(head);

(三) 代码输出和算法复杂度

输出:

复制代码
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11

时间复杂度:O (n×k²)。总共有 n×k 个节点(假设每条链表有 O (n) 个节点),而找到最小节点需要遍历 k 次,因此处理所有 n×k 个节点总耗时为 n×k×k。

空间复杂度:O(1)。

四、【优化解法-1】使用最小堆 ------ 时间复杂度 O (n²),空间复杂度 O (1)

(一) 解法思路

该解法主要是对前一种方法的优化。我们不再通过线性遍历数组 来查找最小值,而是使用最小堆 数据结构,将这一步操作的时间复杂度降低到 O(log k)

(二) 使用 5 种语言实现

1. C++

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node(int x) {
        data = x;
        next = nullptr;
    }
};

// 用于最小堆的自定义比较器
class Compare {
public:
    bool operator()(Node* a, Node* b) {
        return a->data > b->data;
    }
};

// 合并 K 个有序链表的函数
Node* mergeKLists(vector<Node*>& arr) {
    
    // 定义最小堆
    priority_queue<Node*, vector<Node*>, Compare> pq;
    
    // 将 k 个链表的头节点插入堆中
    for (Node* head: arr) {
        if (head != nullptr) pq.push(head);
    }
    
    // 初始化哑节点头
    Node* dummy = new Node(-1);
    Node* tail = dummy;
    
    while (!pq.empty()) {
        
        // 取出堆顶的最小节点
        Node* top = pq.top();
        pq.pop();
        
        // 将该节点添加到结果链表
        tail->next = top;
        tail = top;
        
        // 如果该节点存在后继节点,则将其加入堆
        if (top->next!=nullptr) {
            pq.push(top->next);
        }
    }
    
    // 返回合并后的链表
    return dummy->next;
}

void printList(Node* node) {
    while (node != nullptr) {
        cout << node->data;
        if(node->next) cout << "->";
        node = node->next;
    }
}

int main() {
    int k = 3; 
  
    vector<Node*> arr(k);

    arr[0] = new Node(1);
    arr[0]->next = new Node(3);
    arr[0]->next->next = new Node(5);
    arr[0]->next->next->next = new Node(7);

    arr[1] = new Node(2);
    arr[1]->next = new Node(4);
    arr[1]->next->next = new Node(6);
    arr[1]->next->next->next = new Node(8);

    arr[2] = new Node(0);
    arr[2]->next = new Node(9);
    arr[2]->next->next = new Node(10);
    arr[2]->next->next->next = new Node(11);
    
    Node* head = mergeKLists(arr);

    printList(head);

    return 0;
}

2. Java

java 复制代码
import java.util.List;
import java.util.ArrayList;
import java.util.PriorityQueue;

class Node {
    int data;
    Node next;

    Node(int x) {
        data = x;
        next = null;
    }
}

class DSA {

    // 合并 K 个有序链表的函数
    static Node mergeKLists(List<Node> arr) {
        // 创建最小堆(按节点值升序排列)
        PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> a.data - b.data);

        // 将 k 个链表的头节点插入堆中
        for (Node head : arr) {
            if (head != null) pq.add(head);
        }

        // 初始化哑节点头
        Node dummy = new Node(-1);
        Node tail = dummy;

        while (!pq.isEmpty()) {

            // 取出堆顶的最小节点
            Node top = pq.poll();

            // 将该节点添加到结果链表
            tail.next = top;
            tail = top;

            // 如果该节点存在后继节点,则将其加入堆
            if (top.next != null) {
                pq.add(top.next);
            }
        }

        // 返回合并后的链表
        return dummy.next;
    }

    static void printList(Node node) {
        while (node != null) {
            System.out.print(node.data);
            if(node.next != null){
                System.out.print("->");
            }
            node = node.next;
        }
    }

    public static void main(String[] args) {
        int k = 3;

        List<Node> arr = new ArrayList<>();

        arr.add(new Node(1));
        arr.get(0).next = new Node(3);
        arr.get(0).next.next = new Node(5);
        arr.get(0).next.next.next = new Node(7);

        arr.add(new Node(2));
        arr.get(1).next = new Node(4);
        arr.get(1).next.next = new Node(6);
        arr.get(1).next.next.next = new Node(8);

        arr.add(new Node(0));
        arr.get(2).next = new Node(9);
        arr.get(2).next.next = new Node(10);
        arr.get(2).next.next.next = new Node(11);

        Node head = mergeKLists(arr);

        printList(head);
    }
}

3. Python

python 复制代码
import heapq

class Node:
    def __init__(self, x):
        self.data = x
        self.next = None

# 合并 K 个有序链表的函数
def mergeKLists(arr):
    pq = []
    
    # 将 k 个链表的头节点插入最小堆
    for i in range(0, len(arr)):
        head = arr[i]
        if head is not None:
            heapq.heappush(pq, (head.data, i, head))
    
    # 初始化哑节点头
    dummy = Node(-1)
    tail = dummy

    while pq:
        
        # 取出堆顶的最小节点
        _, index, top = heapq.heappop(pq)
        
        # 将该节点添加到结果链表
        tail.next = top
        tail = top
        
        # 如果该节点存在后继节点,则将其加入堆
        if top.next is not None:
            heapq.heappush(pq, (top.next.data, index, top.next))

    # 返回合并后的链表
    return dummy.next

def printList(node):
    while node is not None:
        print(node.data, end="")
        if node.next is not None:
            print("->", end="")
        node = node.next
    print()

if __name__ == "__main__":
    k = 3

    arr = [None] * k

    arr[0] = Node(1)
    arr[0].next = Node(3)
    arr[0].next.next = Node(5)
    arr[0].next.next.next = Node(7)

    arr[1] = Node(2)
    arr[1].next = Node(4)
    arr[1].next.next = Node(6)
    arr[1].next.next.next = Node(8)

    arr[2] = Node(0)
    arr[2].next = Node(9)
    arr[2].next.next = Node(10)
    arr[2].next.next.next = Node(11)

    head = mergeKLists(arr)

    printList(head)

4. C#

cs 复制代码
using System;
using System.Collections.Generic;

class Node {
    public int data;
    public Node next;

    public Node(int x) {
        data = x;
        next = null;
    }
}

// 最小堆使用的自定义比较器类
class NodeComparer : IComparer<Node> {
    public int Compare(Node a, Node b) {
        if (a.data > b.data)
            return 1;
        else if (a.data < b.data)
            return -1;
        return 0;
    }
}

class DSA {

    // 合并 K 个有序链表的函数
    static Node mergeKLists(List<Node> arr) {
        PriorityQueue<Node> pq = new PriorityQueue<Node>(new NodeComparer());

        // 将 k 个链表的头节点插入堆中
        foreach (Node head in arr) {
            if (head != null) pq.Enqueue(head);
        }

        // 初始化哑节点头
        Node dummy = new Node(-1);
        Node tail = dummy;

        while (pq.Count > 0) {

            // 取出堆顶的最小节点
            Node top = pq.Dequeue();

            // 将该节点添加到结果链表
            tail.next = top;
            tail = top;

            // 如果该节点存在后继节点,则将其加入堆
            if (top.next != null) {
                pq.Enqueue(top.next);
            }
        }

        // 返回合并后的链表
        return dummy.next;
    }

    static void printList(Node node) {
        while (node != null) {
            Console.Write(node.data);
            if(node.next != null){
                Console.Write("->");
            }
            node = node.next;
        }
    }

    static void Main(string[] args) {

        List<Node> arr = new List<Node>();

        arr.Add(new Node(1));
        arr[0].next = new Node(3);
        arr[0].next.next = new Node(5);
        arr[0].next.next.next = new Node(7);

        arr.Add(new Node(2));
        arr[1].next = new Node(4);
        arr[1].next.next = new Node(6);
        arr[1].next.next.next = new Node(8);

        arr.Add(new Node(0));
        arr[2].next = new Node(9);
        arr[2].next.next = new Node(10);
        arr[2].next.next.next = new Node(11);

        Node head = mergeKLists(arr);

        printList(head);
    }
}

// 自定义优先队列(最小堆)
class PriorityQueue<T> {
    private List<T> heap;
    private IComparer<T> comparer;

    public PriorityQueue(IComparer<T> comparer = null) {
        this.heap = new List<T>();
        this.comparer = comparer ?? Comparer<T>.Default;
    }

    public int Count => heap.Count;

    // 入队操作
    public void Enqueue(T item) {
        heap.Add(item);
        int i = heap.Count - 1;
        while (i > 0) {
            int parent = (i - 1) / 2;
            if (comparer.Compare(heap[parent], heap[i]) <= 0)
                break;
            Swap(parent, i);
            i = parent;
        }
    }

    // 出队操作
    public T Dequeue() {
        if (heap.Count == 0)
            throw new InvalidOperationException("Priority queue is empty.");
        T result = heap[0];
        int last = heap.Count - 1;
        heap[0] = heap[last];
        heap.RemoveAt(last);
        last--;
        int i = 0;
        while (true) {
            int left = 2 * i + 1;
            if (left > last)
                break;
            int right = left + 1;
            int minChild = left;
            if (right <= last && comparer.Compare(heap[right], heap[left]) < 0)
                minChild = right;
            if (comparer.Compare(heap[i], heap[minChild]) <= 0)
                break;
            Swap(i, minChild);
            i = minChild;
        }
        return result;
    }

    // 交换堆中两个元素
    private void Swap(int i, int j) {
        T temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }
}

5. JavaScript

javascript 复制代码
class Node {
    constructor(x) {
        this.data = x;
        this.next = null;
    }
}

// 用于最小堆的节点比较器
function nodeComparator(k1, k2) {
  if (k1.data > k2.data) return -1;
  if (k1.data < k2.data) return 1;
  return 0;
}

// 优先队列(最小堆)实现
class PriorityQueue {
  constructor(compare) {
    this.heap = [];
    this.compare = compare;
  }

  enqueue(value) {
    this.heap.push(value);
    this.bubbleUp();
  }

  bubbleUp() {
    let index = this.heap.length - 1;
    while (index > 0) {
      let element = this.heap[index],
        parentIndex = Math.floor((index - 1) / 2),
        parent = this.heap[parentIndex];
      if (this.compare(element, parent) < 0) break;
      this.heap[index] = parent;
      this.heap[parentIndex] = element;
      index = parentIndex;
    }
  }

  dequeue() {
    let max = this.heap[0];
    let end = this.heap.pop();
    if (this.heap.length > 0) {
      this.heap[0] = end;
      this.sinkDown(0);
    }
    return max;
  }

  sinkDown(index) {
    let left = 2 * index + 1,
      right = 2 * index + 2,
      largest = index;

    if (
      left < this.heap.length &&
      this.compare(this.heap[left], this.heap[largest]) > 0
    ) {
      largest = left;
    }

    if (
      right < this.heap.length &&
      this.compare(this.heap[right], this.heap[largest]) > 0
    ) {
      largest = right;
    }

    if (largest !== index) {
      [this.heap[largest], this.heap[index]] = [
        this.heap[index],
        this.heap[largest],
      ];
      this.sinkDown(largest);
    }
  }

  isEmpty() {
    return this.heap.length === 0;
  }
}

// 合并 K 个有序链表的函数
function mergeKLists(arr) {
    const pq = new PriorityQueue(nodeComparator);

    // 将 k 个链表的头节点插入堆中
    for (let head of arr) {
        if (head !== null) pq.enqueue(head);
    }

    // 初始化哑节点头
    let dummy = new Node(-1);
    let tail = dummy;

    while (!pq.isEmpty()) {

        // 取出堆顶的最小节点
        let top = pq.dequeue();

        // 将该节点添加到结果链表
        tail.next = top;
        tail = top;

        // 如果该节点存在后继节点,则将其加入堆
        if (top.next !== null) {
            pq.enqueue(top.next);
        }
    }

    // 返回合并后的链表
    return dummy.next;
}

function printList(node) {
    while (node !== null) {
        process.stdout.write(node.data.toString());
        if (node.next !== null) {
            process.stdout.write("->");
        }
        node = node.next;
    }
    console.log(); 
}

let k = 3;

let arr = [];

arr[0] = new Node(1);
arr[0].next = new Node(3);
arr[0].next.next = new Node(5);
arr[0].next.next.next = new Node(7);

arr[1] = new Node(2);
arr[1].next = new Node(4);
arr[1].next.next = new Node(6);
arr[1].next.next.next = new Node(8);

arr[2] = new Node(0);
arr[2].next = new Node(9);
arr[2].next.next = new Node(10);
arr[2].next.next.next = new Node(11);

let head = mergeKLists(arr);

printList(head);

(三) 代码输出和算法复杂度

输出:

复制代码
0->1->2->3->4->5->6->7->8->9->10->11

时间复杂度:O (n × log k),其中 n 是所有链表的节点总数。

空间复杂度:O (k),这是由堆占用的空间。堆中在任意时刻最多只存储 k 个元素。

五、【优化解法-2】使用分治法 ------ 时间复杂度 O (n),空间复杂度 O (n)

(一) 解法思路

该方法的核心思路是采用分治法

  1. 递归地将 k 个链表分成两半,直到形成可以两两合并的链表对
  2. 使用二路归并(类似归并排序的合并步骤)将这些链表对合并
  3. 自底向上重复合并过程,直到所有链表合并为一个有序链表

分步实现思路:

  1. k 个链表分成两部分:左半部分 lists[0...mid] 和右半部分 lists[mid+1...end]
  2. 递归合并左半部分链表,得到第一个有序链表
  3. 递归合并右半部分链表,得到第二个有序链表
  4. 使用双指针法合并上述两个有序链表。
  5. 返回最终合并完成的有序链表。

(二) 使用 5 种语言实现

1. C++

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node(int x) {
        data = x;
        next = nullptr;
    }
};

// 合并两个有序链表的函数
Node* mergeTwo(Node* head1, Node* head2) {
  
    // 创建哑节点简化合并流程
    Node* dummy = new Node(-1);
    Node* curr = dummy;

    // 同时遍历两个链表
    while (head1 != nullptr && head2 != nullptr) {
      
        // 将较小的节点加入合并后的链表
        if (head1->data <= head2->data) {
            curr->next = head1;
            head1 = head1->next;
        } else {
            curr->next = head2;
            head2 = head2->next;
        }
        curr = curr->next;
    }

    // 拼接剩余未遍历完的链表部分
    if (head1 != nullptr) {
        curr->next = head1;
    } else {
        curr->next = head2;
    }

    // 返回合并后的链表(跳过哑节点)
    return dummy->next;
}

// 分治递归合并函数
Node* mergeListsRecur(int i, int j, vector<Node*> &arr) {
    
    // 只剩一个链表时直接返回
    if (i == j) return arr[i];
    
    // 计算中间位置
    int mid = i + (j-i)/2;
    
    // 递归合并左半部分
    Node* head1 = mergeListsRecur(i, mid, arr);
    
    // 递归合并右半部分
    Node* head2 = mergeListsRecur(mid+1, j, arr);
    
    // 合并最终的两个有序链表
    Node* head = mergeTwo(head1, head2);
    
    return head;
}

// 合并 K 个有序链表的主函数
Node* mergeKLists(vector<Node*>& arr) {
    
    // 空链表特殊处理
    if (arr.size()==0) return nullptr;
  
    return mergeListsRecur(0, arr.size()-1, arr);
}

// 打印链表
void printList(Node* node) {
    while (node != nullptr) {
        cout << node->data;
        if(node->next)
        cout<<" -> ";
        node = node->next;
    }
}

// 主函数测试
int main() {
    int k = 3; 
  
    vector<Node*> arr(k);

    arr[0] = new Node(1);
    arr[0]->next = new Node(3);
    arr[0]->next->next = new Node(5);
    arr[0]->next->next->next = new Node(7);

    arr[1] = new Node(2);
    arr[1]->next = new Node(4);
    arr[1]->next->next = new Node(6);
    arr[1]->next->next->next = new Node(8);

    arr[2] = new Node(0);
    arr[2]->next = new Node(9);
    arr[2]->next->next = new Node(10);
    arr[2]->next->next->next = new Node(11);
    
    Node* head = mergeKLists(arr);

    printList(head);

    return 0;
}

2. Java

java 复制代码
import java.util.List;

class Node {
    int data;
    Node next;

    Node(int x) {
        data = x;
        next = null;
    }
}

class DSA {

    // 合并两个有序链表
    static Node mergeTwo(Node head1, Node head2) {

        // 创建哑节点简化合并
        Node dummy = new Node(-1);
        Node curr = dummy;

        // 双指针遍历两个链表
        while (head1 != null && head2 != null) {

            // 把较小节点接到结果上
            if (head1.data <= head2.data) {
                curr.next = head1;
                head1 = head1.next;
            } else {
                curr.next = head2;
                head2 = head2.next;
            }
            curr = curr.next;
        }

        // 拼接剩余部分
        if (head1 != null) {
            curr.next = head1;
        } else {
            curr.next = head2;
        }

        // 返回合并后的链表
        return dummy.next;
    }

    // 分治递归合并
    static Node mergeListsRecur(int i, int j, List<Node> arr) {

        // 只剩一个链表直接返回
        if (i == j) return arr.get(i);

        // 找中点
        int mid = i + (j - i) / 2;

        // 递归合并左半部分
        Node head1 = mergeListsRecur(i, mid, arr);

        // 递归合并右半部分
        Node head2 = mergeListsRecur(mid + 1, j, arr);

        // 合并两个结果
        Node head = mergeTwo(head1, head2);

        return head;
    }

    // 合并 K 个有序链表主函数
    static Node mergeKLists(List<Node> arr) {

        // 空列表处理
        if (arr.size() == 0) return null;

        return mergeListsRecur(0, arr.size() - 1, arr);
    }

    // 打印链表
    static void printList(Node node) {
        while (node != null) {
            System.out.print(node.data);
            if(node.next!=null)
            {
                System.out.print(" -> ");
            }
            node = node.next;
        }
    }

    public static void main(String[] args) {
        int k = 3;

        List<Node> arr = new java.util.ArrayList<>();

        arr.add(new Node(1));
        arr.get(0).next = new Node(3);
        arr.get(0).next.next = new Node(5);
        arr.get(0).next.next.next = new Node(7);

        arr.add(new Node(2));
        arr.get(1).next = new Node(4);
        arr.get(1).next.next = new Node(6);
        arr.get(1).next.next.next = new Node(8);

        arr.add(new Node(0));
        arr.get(2).next = new Node(9);
        arr.get(2).next.next = new Node(10);
        arr.get(2).next.next.next = new Node(11);

        Node head = mergeKLists(arr);

        printList(head);
    }
}

3. Python

python 复制代码
class Node:
    def __init__(self, x):
        self.data = x
        self.next = None

# 合并两个有序链表的函数
def mergeTwo(head1, head2):
    
    # 创建哑节点简化合并逻辑
    dummy = Node(-1)
    curr = dummy

    # 双指针遍历两个链表
    while head1 is not None and head2 is not None:
      
        # 把较小的节点加入结果链表
        if head1.data <= head2.data:
            curr.next = head1
            head1 = head1.next
        else:
            curr.next = head2
            head2 = head2.next
        curr = curr.next

    # 拼接剩余未遍历完的部分
    if head1 is not None:
        curr.next = head1
    else:
        curr.next = head2

    # 返回合并后的链表(跳过哑节点)
    return dummy.next

# 分治递归合并主逻辑
def mergeListsRecur(i, j, arr):
    
    # 只剩一个链表时直接返回
    if i == j:
        return arr[i]

    # 计算中点,分割数组
    mid = i + (j - i) // 2

    # 递归合并左半边
    head1 = mergeListsRecur(i, mid, arr)

    # 递归合并右半边
    head2 = mergeListsRecur(mid + 1, j, arr)

    # 合并最终两个有序链表
    head = mergeTwo(head1, head2)

    return head

# 合并 K 个有序链表的入口函数
def mergeKLists(arr):
    
    # 处理空链表情况
    if len(arr) == 0:
        return None

    return mergeListsRecur(0, len(arr) - 1, arr)

# 打印链表
def printList(node):
    while node is not None:
        print(f"{node.data}", end="")
        if node.next is not None:
            print(" -> ", end="")
        node = node.next
    print()

# 测试主程序
if __name__ == "__main__":
    k = 3

    arr = [None] * k

    arr[0] = Node(1)
    arr[0].next = Node(3)
    arr[0].next.next = Node(5)
    arr[0].next.next.next = Node(7)

    arr[1] = Node(2)
    arr[1].next = Node(4)
    arr[1].next.next = Node(6)
    arr[1].next.next.next = Node(8)

    arr[2] = Node(0)
    arr[2].next = Node(9)
    arr[2].next.next = Node(10)
    arr[2].next.next.next = Node(11)

    head = mergeKLists(arr)

    printList(head)

4. C#

cs 复制代码
using System;
using System.Collections.Generic;

class Node {
    public int data;
    public Node next;

    public Node(int x) {
        data = x;
        next = null;
    }
}

class DSA {

    // 合并两个有序链表
    static Node mergeTwo(Node head1, Node head2) {

        // 创建哑节点简化合并
        Node dummy = new Node(-1);
        Node curr = dummy;

        // 双指针遍历两个链表
        while (head1 != null && head2 != null) {

            // 把较小节点接到结果上
            if (head1.data <= head2.data) {
                curr.next = head1;
                head1 = head1.next;
            } else {
                curr.next = head2;
                head2 = head2.next;
            }
            curr = curr.next;
        }

        // 拼接剩余部分
        if (head1 != null) {
            curr.next = head1;
        } else {
            curr.next = head2;
        }

        // 返回合并后的链表
        return dummy.next;
    }

    // 分治递归合并
    static Node mergeListsRecur(int i, int j, List<Node> arr) {

        // 只剩一个链表直接返回
        if (i == j) return arr[i];

        // 找中点
        int mid = i + (j - i) / 2;

        // 递归合并左半部分
        Node head1 = mergeListsRecur(i, mid, arr);

        // 递归合并右半部分
        Node head2 = mergeListsRecur(mid + 1, j, arr);

        // 合并两个结果
        Node head = mergeTwo(head1, head2);

        return head;
    }

    // 合并 K 个有序链表主函数
    static Node mergeKLists(List<Node> arr) {

        // 空列表处理
        if (arr.Count == 0) return null;

        return mergeListsRecur(0, arr.Count - 1, arr);
    }

    // 打印链表
    static void printList(Node head) {
        Node temp = head;
        while (temp != null) {
            Console.Write(temp.data);
            if(temp.next != null)
                Console.Write(" -> ");
            temp = temp.next;
        }
        Console.WriteLine();
    }

    static void Main(string[] args) {

        List<Node> arr = new List<Node>();

        arr.Add(new Node(1));
        arr[0].next = new Node(3);
        arr[0].next.next = new Node(5);
        arr[0].next.next.next = new Node(7);

        arr.Add(new Node(2));
        arr[1].next = new Node(4);
        arr[1].next.next = new Node(6);
        arr[1].next.next.next = new Node(8);

        arr.Add(new Node(0));
        arr[2].next = new Node(9);
        arr[2].next.next = new Node(10);
        arr[2].next.next.next = new Node(11);

        Node head = mergeKLists(arr);

        printList(head);
    }
}

5. JavaScript

javascript 复制代码
class Node {
    constructor(x) {
        this.data = x;
        this.next = null;
    }
}

// 合并两个有序链表
function mergeTwo(head1, head2) {

    // 创建哑节点,方便拼接
    let dummy = new Node(-1);
    let curr = dummy;

    // 双指针遍历两个链表
    while (head1 !== null && head2 !== null) {

        // 选择较小节点加入结果
        if (head1.data <= head2.data) {
            curr.next = head1;
            head1 = head1.next;
        } else {
            curr.next = head2;
            head2 = head2.next;
        }
        curr = curr.next;
    }

    // 拼接剩余部分
    if (head1 !== null) {
        curr.next = head1;
    } else {
        curr.next = head2;
    }

    // 返回合并后的链表
    return dummy.next;
}

// 分治递归:合并区间 [i, j] 的所有链表
function mergeListsRecur(i, j, arr) {

    // 只剩一个链表,直接返回
    if (i === j) return arr[i];

    // 找中点
    let mid = i + Math.floor((j - i) / 2);

    // 递归合并左半部分
    let head1 = mergeListsRecur(i, mid, arr);

    // 递归合并右半部分
    let head2 = mergeListsRecur(mid + 1, j, arr);

    // 合并两个有序链表
    return mergeTwo(head1, head2);
}

// 主函数:合并 K 个有序链表
function mergeKLists(arr) {

    // 空数组处理
    if (arr.length === 0) return null;

    return mergeListsRecur(0, arr.length - 1, arr);
}

// 打印链表
function printList(node) {
    while (node !== null) {
        process.stdout.write(node.data.toString());
        if (node.next !== null) {
            process.stdout.write(" -> ");
        }
        node = node.next;
    }
}

// 测试用例
let k = 3;
let arr = [];

arr[0] = new Node(1);
arr[0].next = new Node(3);
arr[0].next.next = new Node(5);
arr[0].next.next.next = new Node(7);

arr[1] = new Node(2);
arr[1].next = new Node(4);
arr[1].next.next = new Node(6);
arr[1].next.next.next = new Node(8);

arr[2] = new Node(0);
arr[2].next = new Node(9);
arr[2].next.next = new Node(10);
arr[2].next.next.next = new Node(11);

let head = mergeKLists(arr);
printList(head);

(三) 代码输出和算法复杂度

输出:

复制代码
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11

时间复杂度:O (n × k × log k),其中 n 是最长链表中的节点数量。

空间复杂度:O (log k),由递归调用栈占用。

相关推荐
风止何安啊2 小时前
手写 URL 解析器,面试官到底想考什么?
前端·javascript·面试
Liangwei Lin2 小时前
LeetCode 20. 有效的括号
算法
IronMurphy2 小时前
【算法四十四】322. 零钱兑换
算法
凯瑟琳.奥古斯特2 小时前
力扣2760 C++滑动窗口解法
数据结构·c++·算法·leetcode·职场和发展
Hesionberger2 小时前
LeetCode96: 不同的二叉搜索树(多解)
算法
_深海凉_2 小时前
LeetCode热题100-不同路径
算法·leetcode·职场和发展
ZPC82102 小时前
CPU 核心隔离 + 线程绑核 + 实时优先级 SCHED_FIFO
人工智能·算法·计算机视觉·机器人
andafaAPS3 小时前
安达发|aps自动排产排程排单软件:日化生产高效运转“数字魔法”
大数据·人工智能·算法·aps软件·安达发aps·aps自动排产排程排单软件
黎阳之光3 小时前
全域实景立体管控:数字孪生与视频孪生技术体系白皮书
大数据·人工智能·算法·安全·数字孪生