每天一道LeetCode-----合并两个/多个有序链表为一个新链表

Merge Sorted Array

原题链接Merge Sorted Array
这里写图片描述
意思是给定两个有序数组,将其合并成一个有序数组,存在nums1中。


如果先只是简单合并成一个新数组,然后将新数组赋值给nums1,基本就算完成了。现在考虑不适用其它内存空间,在nums1上原地合并新数组。
遇到的问题是如果nums1[i] > nums2[j],那么nums1[i]的位置就应该被赋值给nums2[j],可是nums1[i]原先的值应该放在哪里呢,接下来还有用这个nums1[i]和nums2[j+1]继续比较呢。如果nums1[i]一直大于nums2[j],那么所有的nums1[i]又应该放在哪里呢。
方法是在开始合并前就给nums1的前面留出n个大小的空间,而把nums1原来的数据全移动到后面的位置(这里是移动到nums1[n : m+n)),这样,即使nums2全都小于nums1,nums2也可以原封不动的放进nums1中,并且不需要移动nums1原有的数据

0   1   2   3   4   5   下标
1   3   5               nums1
2   4   6               nums2

初始时
0   1   2   3   4   5   下标
            1   3   5   nums1
2   4   6               nums2

开始合并
0   1   2   3   4   5   下标
1           1   3   5   nums1
2   4   6               nums2
------------------------------
1   2       1   3   5   nums1
2   4   6               nums2
------------------------------
1   2   3   1   3   5   nums1
2   4   6               nums2
------------------------------
1   2   3   4   3   5   nums1
2   4   6               nums2
------------------------------
1   2   3   4   5   5   nums1
2   4   6               nums2
------------------------------
1   2   3   4   5   6   nums1
2   4   6               nums2
------------------------------
合并完成

因为初始时nums1前面已经留有n个大小的空间(nums2的大小),所以在给nums1[0 : m+1)赋值时覆盖的都是合并完成,被放到前面的数据,不会丢失数据
代码如下

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        for(int i = m - 1; i >= 0; --i)
            nums1[i + n] = nums1[i];

        int p1 = n;
        int p2 = 0;
        int idx = 0;
        while(p1 < m + n && p2 < n)
        {
            nums1[idx++] = (nums1[p1] > nums2[p2]) ? nums2[p2++] : nums1[p1++];
        }
        while(p1 < m + n)
            nums1[idx++] = nums1[p1++];
        while(p2 < n)
            nums1[idx++] = nums2[p2++];
    }
};

Merge Two Sorted Lists

原题链接Merge Two Sorted Lists
这里写图片描述
意思是合并两个有序链表成为一个新的有序链表,比较简单,依次比较即可
细节方法是构造一个头节点,可以解决返回值是null的情况

/**
 * 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* header = new ListNode(-1);
        ListNode* cur = header;
        while(l1 || l2)
        {
            int n = 0;
            if(l1 == NULL || (l1 && l2 && l1->val > l2->val))
            {
                n = l2->val;
                l2 = l2->next;
            }
            else if(l2 == NULL || (l1 && l2 && l1->val <= l2->val))
            {
                n = l1->val;
                l1 = l1->next;
            }

            cur->next = new ListNode(n);
            cur = cur->next;
        }

        ListNode *ans = header->next;
        delete header;
        return ans;
    }
};

Merge k Sorted Lists

原题链接Merge k Sorted Lists
这里写图片描述
意思是合并k个有序链表,要求合成的链表也是有序的
两个链表时可以每次比较大小决定取哪个链表的值,k个就不能这么乱来了,不然复杂度会飙升。
可以维护一定大小的最小堆(优先级队列),堆中元素是ListNode类型,每次取最小的,然后插入取出的节点的下一个节点(如果是null就不用插入),直到堆变空为止。
需要注意的是如果ListNode设计时内部重载了operator<函数,那么直接创建优先级队列即可。但是题中给出的ListNode定义没有提供这样的函数,就需要自己实现,此时如果使用优先级队列的话,模板参数要提供三个

/**
 * 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) {
        if(lists.size() == 0)
            return NULL;
        /*
         * 三个模板参数
         * ListNode,存储的元素类型
         * vector<ListNode>,内部存储方式,默认是vector,传入vector就好
         * cmp,因为没有提供比较大小的函数,需要自己提供,但是不能简单的创建一个函数,需要一个函数对象(行为像函数的类),即重载了operator()的类
         */
        std::priority_queue<ListNode, vector<ListNode>, cmp> pq;

        for(auto node : lists)
        {
            if(node != NULL)
                pq.push(std::move(*node));
        }

        ListNode* header = new ListNode(-1);
        ListNode* cur = header;
        while(pq.size() > 0)
        {
            ListNode node = pq.top();
            pq.pop();
            cur->next = new ListNode(node.val);
            cur = cur->next;
            if(node.next)
                pq.push(std::move(*node.next));
        }

        ListNode* ans = header->next;
        delete header;
        return ans;
    }

private:
    struct cmp
    {
        /* 
         * 如果是增序,就判断是否大于
         * 如果是减序,就判断是否小于
         * 真怪...
         */
        bool operator()(const ListNode& lhs, const ListNode& rhs)
        {
            return lhs.val > rhs.val;
        }  
    };
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值