题解 | #合并两个有序的数组#

合并两个有序的数组

http://www.nowcoder.com/practice/89865d4375634fc484f3a24b7fe65665

@TOC

一、题目描述

NC22合并两个有序的数组
原题链接https://www.nowcoder.com/practice/89865d4375634fc484f3a24b7fe65665?tpId=117
题目大意:给定递增数组A,B,合并A,B的元素,使合并过后的数组是递增的,并且存放在数组A中
注意审题:题目中有一句话:可以假设A数组有足够的空间存放 B数组的元素,即无需考虑溢出问题,或理解为A数组空间足够

二、算法1

算法思路

  1. 总体思想:归并排序思想
  2. 该算法空间复杂度为,时间复杂度
  3. 开辟一个新数组C,定义指针i,j,p,其中三个指针分别指向A,B,C的开头,即i=j=p=0(注意此处的指针并不是C语言中的指针,此处代表指向一个位置的int变量)
  4. 比较i,j所指向的元素,如果A[i]<=B[j],则将A[i]放入C中,否则将B[j]放入C中,即C[p++]=A[i]<=B[j]?A[i++]:B[j++],直到有一个数组为空,或者两个同时为空
  5. 接着再将有剩余的那个数组的元素转移到C中即可
  6. 因为题目要求,最后将C数组拷贝到A数组中

代码实现

class Solution {
public:
    void merge(int A[], int m, int B[], int n) {
          int i=0,j=0,p=0; 
        int c[m+n];//定义辅助数组C 
        while(i<m&&j<n){
            c[p++]=A[i]<=B[j]?A[i++]:B[j++];//将A[i]和B[j]中小的那个丢入C中 
        }      
        while(i<m){//如果A中有剩余 
            c[p++]=A[i++];
        }
        while(j<n){//如果B中有剩余 
            c[p++]=B[j++];
        }
        for(int i=0;i<p;i++)A[i]=c[i];//因为题目要求,将C数组拷贝到A数组中 
    }
};

三、算法2

算法思路

  1. 较上一个算法,因为A的空间充足,所以我们可以直接在A中进行操作
  2. 定义指针i,j,p,(此处指针意义同上),i,j指针指向原末尾,p指针指向合并后的A末尾 ,即i=m-1,j=n-1,p=m+n-1
  3. 整体思路:比较A[i]和B[j],其中大的,丢到A[p]中,然后p和该指针左移一格。空间复杂度为,时间复杂度,较上一个算法空间复杂度得到了优化。
  4. 这个时候,就会有同学好奇,会不会出现A[x]还没有填写,但是被覆盖的情况,最后造成A[x]丢失,以至于答案错误的情况?,答案是显然的,既然算法是正确的,那么这种情况就必然不可能出现,下面简单证明一下。
  5. 我们反过来思考,出现上面情况的原因是什么,什么时候会出现?显然是p<i时候,才会造成一个没填入,但是被覆盖的情况
  6. 证明:因为A原本是递增的,所以该情况,p移动的比i多,j指针最多导致p移动n次,此时p=m,而i指针和p指针同时移动时候不会改变p,i之间大小的关系,所以永远有p>=i
  7. 既然算法正确,那么代码也不难理解,跟算法1很相似while(~i&&~j)A[p--]=A[i]>B[j]?A[i--]:B[j--];
  8. 此处~i等价i>=0,因为-1取反过后返回的是0,所以~i的意思就是i!=-1,因为此处是从正轴向左走,所以i!=-1等价i>=0,位运算一般情况比其他运算符速度要快,这也是一种小小优化程序的方法
  9. 最后处理A,B剩余情况,B数组剩余,显然应该将B剩下的丢入A中,但是A剩余我们还需要操作吗?
  10. 答案是不用的,因为此时有'p==i',剩下的一模一样,我们就不需要转移了(此处如果没有看懂的同学,可以看代码中的注释,此处结合代码讲解比较容易理解)

    动画演示

    图片说明

    代码实现

    C++代码

    class Solution {
    public:
        void merge(int A[], int m, int B[], int n) {
            int i=m-1,j=n-1,p=m+n-1;//i,j指针指向原末尾,p指针指向合并后的A末尾 
            while(~i&&~j) {// ~i  <==> i>=0,因为-1取反过后返回的是0,位运算一般情况比其他运算符速度要快 
                A[p--]=A[i]>B[j]?A[i--]:B[j--];//合并A、B数组, 比较i,j指针指向的元素,将大的那个丢进去 
            }
            while(~j){//如果B数组还有剩余,则直接全部移到A数组中 
                A[p--]=B[j--];
            }
            /*此处如果出现A数组有剩余的情况,理论上应该执行while(i>=0)A[p--]=A[i--]
            但是如果A有剩余必然有p==i(出现剩余的情况,只有可能一个出现剩余,不可能出现AB数组都剩余的情况) 
            (如果出现AB都剩余,就跟第一个for循环矛盾了) 
            既然对于指针p==i,那么此时这个while循环就会显得很多余                     
            */    
        }
    };

Python代码

class Solution:
    def merge(self ,A,m,B,n):
        i=m-1
        j=n-1
        p=m+n-1 #i,j指针指向原末尾,p指针指向合并后的A末尾 
        while i>=0 and j>=0 :# 合并A、B数组, 比较i,j指针指向的元素,将大的那个丢进去 
            if A[i]>B[j]:
                A[p]=A[i]
                p-=1
                i-=1
            else :
                A[p]=B[j]
                p-=1
                j-=1
        while j>=0 :# 如果B数组还有剩余,则直接全部移到A数组中 
            A[p]=B[j]
            p-=1
            j-=1
全部评论
算法2的空间复杂度应该是O(1)吧
1
送花
回复
分享
发布于 2022-01-24 20:37
讲得很细致,看别人的解答都没有说为啥不考虑A中有剩余的情况,在你这里看明白了!
3
送花
回复
分享
发布于 2021-06-19 14:25
秋招专场
校招火热招聘中
官网直投
算法2的细节真好
点赞
送花
回复
分享
发布于 2021-08-22 11:22

相关推荐

46 5 评论
分享
正在热议
# 牛客帮帮团来啦!有问必答 #
1152069次浏览 17149人参与
# 通信和硬件还有转码的必要吗 #
11209次浏览 101人参与
# OPPO开奖 #
19224次浏览 267人参与
# 和牛牛一起刷题打卡 #
19023次浏览 1635人参与
# 实习与准备秋招该如何平衡 #
203428次浏览 3627人参与
# 大厂无回复,继续等待还是奔赴小厂 #
4975次浏览 30人参与
# 不去互联网可以去金融科技 #
20477次浏览 256人参与
# 通信硬件薪资爆料 #
265968次浏览 2484人参与
# 国企是理工四大天坑的最好选择吗 #
2227次浏览 34人参与
# 互联网公司评价 #
97718次浏览 1280人参与
# 简历无回复,你会继续海投还是优化再投? #
25039次浏览 354人参与
# 0offer是寒冬太冷还是我太菜 #
454907次浏览 5124人参与
# 国企和大厂硬件兄弟怎么选? #
53918次浏览 1012人参与
# 参加过提前批的机械人,你们还参加秋招么 #
14646次浏览 349人参与
# 硬件人的简历怎么写 #
82290次浏览 852人参与
# 面试被问第一学历差时该怎么回答 #
19401次浏览 213人参与
# 你见过最离谱的招聘要求是什么? #
28194次浏览 248人参与
# 学历对求职的影响 #
161253次浏览 1804人参与
# 你收到了团子的OC了吗 #
538774次浏览 6387人参与
# 你已经投递多少份简历了 #
344269次浏览 4963人参与
# 实习生应该准时下班吗 #
96988次浏览 722人参与
# 听劝,我这个简历该怎么改? #
63525次浏览 622人参与
牛客网
牛客企业服务