关于合并有序链表和数组的问题:

文章目录

  • 1.合并两个有序数组
  • 2.合并两个有序链表
  • 3.合并K个排序链表
      • 思路1:分治法
      • 思路2:最小堆的数据结构

1.合并两个有序数组

将两个按升序排列的数组仍按升序合并存放到另一个数组中,要求每个
数都一次到位,不得在新数组中重新排序。

#include 
int main(void)
{
    int b[5] = {1, 6, 17, 56, 72};
    int a[5] = {7, 23, 32, 33, 82};
    int c[10], i, j, k, p;
    i = j = k = 0;         //i 对应 a 数组,j 对应 b 数组,k 对应 c 数组;
    while (i < 5 && j < 5) //判断 a,b 两数组是否比较完毕;
    {
        if (a[i] < b[j])
            c[k++] = a[i++];
        else
            c[k++] = b[j++];
    }
    if (i > 4) //把 b 赋给 c
    {
        for (p = j; p < 5; p++)
            c[k++] = b[p];
    }
    if (j > 4) //把 a 赋给 c
    {
        for (p = i; p < 5; p++)
            c[k++] = a[p];
    }
    for (i = 0; i < 10; i++) //输出 c
        printf("%4d", c[i]);
    printf("\n");
}

2.合并两个有序链表

*/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
//遍历解法
class Solution
{
  public:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        ListNode result = ListNode(-100);
        ListNode *test = &result;

        ListNode *temp1 = l1;
        ListNode *temp2 = l2;

        while (temp1 && temp2)
        {
            //注意这里判断了相等的情况
            //temp1->val == temp2->val
            if (temp1->val <= temp2->val)
            {
                test->next = temp1;
                temp1 = temp1->next;
                test = test->next;
            }
            else
            {
                test->next = temp2;
                temp2 = temp2->next;
                test = test->next;
            }
        }
        if (temp1)
            test->next = temp1;
        if (temp2)
            test->next = temp2;
        return result.next;
    }
};
//递归解法
class Solution
{
  public:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        if (l1 == NULL)
            return l2;
        if (l2 == NULL)
            return l1;
        //还是判断了相等
        if (l1->val <= l2->val)
        {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else
        {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

3.合并K个排序链表

思路1:分治法

简单来说就是不停的对半划分,比如k个链表先划分为合并两个k/2个链表的任务,再不停的往下划分,直到划分成只有一个或两个链表的任务,才开始进行合并。举个例子来说比如合并6个链表,那么按照分治法,我们首先分别合并0和3,1和4,2和5。这样下一次只需合并3个链表,我们再合并1和3,最后和2合并就可以了。

代码中的k是通过 (n+1)/2 计算的,这里为啥要加1呢,这是为了当n为奇数的时候,k能始终从后半段开始,比如当n=5时,那么此时k=3,则0和3合并,1和4合并,最中间的2空出来。当n是偶数的时候,加1也不会有影响,比如当n=4时,此时k=2,那么0和2合并,1和3合并,完美解决问题.

/**
 * 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 len = lists.size();
        if (len == 0) return NULL;
        while (len > 1) {
            int k = (len + 1) / 2;
            for (int i = 0; i < len / 2; ++i) {
                lists[i] = mergeTwoLists(lists[i], lists[i + k]);
            }
            len = k;
        }
        return lists[0];
    }
private:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        if (l1 == NULL)
            return l2;
        if (l2 == NULL)
            return l1;
        if (l1->val <= l2->val)
        {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        }
        else
        {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};

思路2:最小堆的数据结构

我们再来看另一种解法,这种解法利用了最小堆这种数据结构,我们首先把k个链表的首元素都加入最小堆中,它们会自动排好序。然后我们每次取出最小的那个元素加入我们最终结果的链表中,然后把取出元素的下一个元素再加入堆中,下次仍从堆中取出最小的元素做相同的操作,以此类推,直到堆中没有元素了,此时k个链表也合并为了一个链表,返回首节点即可,代码如下:

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        auto cmp = [](ListNode*& a, ListNode*& b) {
            return a->val > b->val;
        };
        priority_queue<ListNode*, vector<ListNode*>, decltype(cmp) > q(cmp);
        for (auto node : lists) {
            if (node) q.push(node);
        }
        ListNode *dummy = new ListNode(-1), *cur = dummy;
        while (!q.empty()) {
            auto t = q.top(); q.pop();
            cur->next = t;
            cur = cur->next;
            if (cur->next) q.push(cur->next);
        }
        return dummy->next;
    }
};

合并K个排序链表的思路来自:[LeetCode] Merge k Sorted Lists 合并k个有序链表 ,其中还列举许多种解法,可自行查阅.

你可能感兴趣的:(刷题)