@TOC
一、题目描述
NC22合并两个有序的数组
原题链接https://www.nowcoder.com/practice/89865d4375634fc484f3a24b7fe65665?tpId=117
题目大意:给定递增数组A,B,合并A,B的元素,使合并过后的数组是递增的,并且存放在数组A中
注意审题:题目中有一句话:可以假设A数组有足够的空间存放 B数组的元素,即无需考虑溢出问题,或理解为A数组空间足够
二、算法1
算法思路
- 总体思想:归并排序思想
- 该算法空间复杂度为,时间复杂度
- 开辟一个新数组C,定义指针i,j,p,其中三个指针分别指向A,B,C的开头,即
i=j=p=0
(注意此处的指针并不是C语言中的指针,此处代表指向一个位置的int变量) - 比较i,j所指向的元素,如果A[i]<=B[j],则将A[i]放入C中,否则将B[j]放入C中,即
C[p++]=A[i]<=B[j]?A[i++]:B[j++]
,直到有一个数组为空,或者两个同时为空 - 接着再将有剩余的那个数组的元素转移到C中即可
- 因为题目要求,最后将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
算法思路
- 较上一个算法,因为A的空间充足,所以我们可以直接在A中进行操作
- 定义指针i,j,p,(此处指针意义同上),i,j指针指向原末尾,p指针指向合并后的A末尾 ,即
i=m-1,j=n-1,p=m+n-1
- 整体思路:比较A[i]和B[j],其中大的,丢到A[p]中,然后p和该指针左移一格。空间复杂度为,时间复杂度,较上一个算法空间复杂度得到了优化。
- 这个时候,就会有同学好奇,会不会出现A[x]还没有填写,但是被覆盖的情况,最后造成A[x]丢失,以至于答案错误的情况?,答案是显然的,既然算法是正确的,那么这种情况就必然不可能出现,下面简单证明一下。
- 我们反过来思考,出现上面情况的原因是什么,什么时候会出现?显然是p<i时候,才会造成一个没填入,但是被覆盖的情况
- 证明:因为A原本是递增的,所以该情况,p移动的比i多,j指针最多导致p移动n次,此时p=m,而i指针和p指针同时移动时候不会改变p,i之间大小的关系,所以永远有p>=i
- 既然算法正确,那么代码也不难理解,跟算法1很相似
while(~i&&~j)A[p--]=A[i]>B[j]?A[i--]:B[j--];
- 此处
~i
等价i>=0
,因为-1取反过后返回的是0,所以~i
的意思就是i!=-1
,因为此处是从正轴向左走,所以i!=-1
等价i>=0
,位运算一般情况比其他运算符速度要快,这也是一种小小优化程序的方法 - 最后处理A,B剩余情况,B数组剩余,显然应该将B剩下的丢入A中,但是A剩余我们还需要操作吗?
- 答案是不用的,因为此时有'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