88. Merge Sorted Array

本文介绍了一种将两个已排序数组合并成一个有序数组的算法实现。该算法特别关注于当一个数组有足够的预留空间来容纳另一个数组元素的情况。文章详细讨论了正确的实现思路,并对比了两种存在错误的代码版本,指出了其缺陷及修正方法。

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.

Subscribe to see which companies asked this question.

惯例翻译题目:

给定两个排序好的整形数组,以及这两个数组中含有的元素个数,注意,这里的数组1,即nums1中的元素数目是m,也就是只计算从第一个开始到第m个。但是数组1的容量是m+n,后面的这n个元素被初始化为0了,而数组2的容量是n。m,n,都是给出的。

先说下后面作对了的思路,一开始采用的方法有错误后面分析;

一开始还要考虑如果数组1的元素个数直接就是0,那么直接

nums1=nums2;

其实这里没考虑n=0的情况,如果n=0;

那就要nums1=nums1;

其实就是直接遍历数组2,从第一个元素开始,从后往前跟数组一作比较;

如果小于或者等于,则将数组一这个元素往后移一位;

如果大于,则跳出里层循环,此时由于已经移位完毕,只需要将此时与nums2[i]比较的nums1[j]的下标j加一;

然后nums[j+1]=nums2[i];

然后比较数组2的下一个元素,这是外层循环了,注意此时数组一的元素个数已经加一,所以要从下标为m+i-1的元素开始比较;

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

这个基本没什么错误;就不赘述了;

以下是错误的代码以及错误实例还有分析:

错误代码以及实例1:

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


重新看了一遍代码然后用实例在纸上做一遍,发现了问题所在,其实思路是对的,思路:

也是从后往前去比较,如果大于或者等于:

1.直接大于或者等于最后一个,插到末尾;

2。大于或者等于第j个,从j+1到m+i-1都要移位,然后插入到j+1位;

如果小于,则要判断是否已经比较到了第0位,否则就会导致比较到第0位没有插入,如果是,则整体移位,然后插入;

不是那就继续循环;

所犯的错误在于移位插入后没有跳出里层循环去比较数组二的下一个元素,而是遍历比较完数组1的所有元素,所以导致输入很奇怪;

添加了两个跳出循环的break;运行结果正确;

修改后的代码:

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i,j,k;
        if(m==0){
            nums1=nums2;
        }
        else{
            for(int i=0;i<n;i++){
            for(int j=m+i-1;j>=0;j--){
                if(nums2[i]>=nums1[j]){
                    if(j==m+i-1){
                        nums1[j+1]=nums2[i];
                        break;
                    }
                    else{
                        for(k=m+i-1;k>=j+1;k--){
                            nums1[k+1]=nums1[k];
                        }
                        nums1[j+1]=nums2[i];
                        break;
                    }
                }
                else{
                    if(j==0){
                        for(int l=m+i-1;l>=0;l--){
                            nums1[l+1]=nums1[l];
                        }
                        nums1[0]=nums2[i];
                        
                    }
                    continue;
                    
                }
            }
        }
        }
        
    }
};

错误代码以及实例2:

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


查看一后再看这个就明了了,思路正确,只是一的反过来而已:

也是从后往前比较,如果小,那么就看是不是比较到第0位了,是就移位再插入到第0位;

否就继续;

如果大于或者等于,就看是不是比最后一位大于等于,是就直接插入到后面;

否就移位然后插入;

错误是一样的,再移位插入或者直接插入后没有跳出这一次的比较;

加入break;后通过;

以下为修改后的代码:

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int i,j,k;
        if(m==0){
            nums1=nums2;
        }
        else{
            for(i=0;i<n;i++){
                for(j=m+i-1;j>=0;j--){
                    if(nums2[i]<nums1[j]){
                        if(j!=0){
                            continue;
                        }
                        else{
                            for(k=m+i-1;k>=0;k--){
                                nums1[k+1]=nums1[k];
                            }
                            nums1[0]=nums2[i];
                            break;
                        }
                    }
                    else{
                        if(j==m+i-1){
                            nums1[j+1]=nums2[i];
                            break;
                        }
                        else{
                             for(k=m+i-1;k>=j+1;k--){
                            nums1[k+1]=nums1[k];
                        }
                        nums1[j+1]=nums2[i];
                        break;
                        }
                       
                    }
                }
            }
            
        }
        
    }
};

To merge k sorted linked lists, one approach is to repeatedly merge two of the linked lists until all k lists have been merged into one. We can use a priority queue to keep track of the minimum element across all k linked lists at any given time. Here's the code to implement this idea: ``` struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; // Custom comparator for the priority queue struct CompareNode { bool operator()(const ListNode* node1, const ListNode* node2) const { return node1->val > node2->val; } }; ListNode* mergeKLists(vector<ListNode*>& lists) { priority_queue<ListNode*, vector<ListNode*>, CompareNode> pq; for (ListNode* list : lists) { if (list) { pq.push(list); } } ListNode* dummy = new ListNode(-1); ListNode* curr = dummy; while (!pq.empty()) { ListNode* node = pq.top(); pq.pop(); curr->next = node; curr = curr->next; if (node->next) { pq.push(node->next); } } return dummy->next; } ``` We start by initializing a priority queue with all the head nodes of the k linked lists. We use a custom comparator that compares the values of two nodes and returns true if the first node's value is less than the second node's value. We then create a dummy node to serve as the head of the merged linked list, and a current node to keep track of the last node in the merged linked list. We repeatedly pop the minimum node from the priority queue and append it to the merged linked list. If the popped node has a next node, we push it onto the priority queue. Once the priority queue is empty, we return the head of the merged linked list. Note that this implementation has a time complexity of O(n log k), where n is the total number of nodes across all k linked lists, and a space complexity of O(k).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值