023 Merge k Sorted Lists [Leetcode]

题目内容:

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

题目分析:
k个排过序的链表,要将它们合并起来就要求能够在较短的时间内将当前的k个数进行排序,并且能够高效得支持数字的增删操作。
可以使用的方法有:败者树,堆排序,这两个算法在插入、删除节点的时候复杂度都为O(n)。

处理流程:
1. 使用每个链表起始的节点,共k个节点,进行堆排序,复杂度 O(klogk)
2. 之后从这k个节点中选择一个最大的,插入到新的链表中去。
3. 被选中的那个链表的节点的下一个节点如果存在,插入到堆中去。
4. 回到步骤2

结束条件为堆中元素少于等于1个,即只有最后一个链表或没有链表剩余。

使用堆的代码:
需要注意的是,priority_queue默认实现的是最大堆,而stl中的比较函数默认是通过“ < <script type="math/tex" id="MathJax-Element-132"><</script>”符号来实现,因此实现最小堆的时候要重写比较函数,将<重写为>。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

struct cmp {
    bool operator()(ListNode *n1, ListNode *n2) {
        return n1->val > n2->val;
    }
};

class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        priority_queue<ListNode *, vector<ListNode *>, cmp> min_heap;

        for(int i = 0; i < lists.size(); ++i) {
            if(lists[i] != NULL)
                min_heap.push(lists[i]);
        }

        ListNode *pre_head(new ListNode(0)), *curr(pre_head);
        while(min_heap.size() > 1) {
            curr->next = min_heap.top();
            min_heap.pop();
            curr = curr->next;
            if(curr->next != NULL)
                min_heap.push(curr->next);
        }

        if(min_heap.size() == 1) {
            curr->next = min_heap.top();
            min_heap.pop();
        }

        ListNode *head = pre_head->next;
        pre_head->next = NULL;
        delete pre_head;

        return head;
    }
};

使用败者树的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        int size = lists.size();
        if (size == 0)
            return NULL;
        int *key = new int[size + 1];
        key[size] = INT_MIN;
        ListNode **elements = new ListNode*[size];

        int *loser = new int[size];
        for (int i = 0; i < size; i++) {
            elements[i] = lists[i];
            loser[i] = size;
            if (elements[i] != NULL)
                key[i] = elements[i]->val;
            else key[i] = INT_MAX;
        }
        for (int i = 0; i < size; i++) {
            adjust(loser, key, i, size);
        }

        ListNode *head = NULL, *curr = NULL;
        while (true) {
            if (key[loser[0]] == INT_MAX) {
                break;
                curr->next = NULL;
            }
            if (head == NULL) {
                head = elements[loser[0]];
                curr = elements[loser[0]];
                elements[loser[0]] = elements[loser[0]]->next;
            }
            else {
                curr->next = elements[loser[0]];
                curr = curr->next;
                elements[loser[0]] = elements[loser[0]]->next;
            }
            if(elements[loser[0]] != NULL)
                key[loser[0]] = elements[loser[0]]->val;
            else 
                key[loser[0]] = INT_MAX;
            adjust(loser, key, loser[0], size);
        }
        return head;
    }

    void adjust(int loser[], int key[], int k, int size) {
        for (int i = (size + k)/2; i > 0; i /= 2) {
            if (key[loser[i]] < key[k]) {
                int temp = k;
                k = loser[i];
                loser[i] = temp;
            }
        }
        loser[0] = k;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值