合并排序数组

来源:互联网 发布:mysql主从好处 编辑:程序博客网 时间:2024/04/30 14:22
在lintcode中关于合并排序数组有两道题目:


1. 合并两个排序的整数数组A和B变成一个新的数组。给出A=[1,2,3,4],B=[2,4,5,6],返回 [1,2,2,3,4,4,5,6]


2. 合并两个排序的整数数组A和B变成一个新的数组。给出A = [1, 2, 3, empty, empty] B = [4,5],合并之后A将变成[1,2,3,4,5]。其中,假设数组A有足够大的空间,也就是说,如果A的非空元素个数为m,B的非空元素个数为n,那么A的空间容量一定是大于等于m+n的


我们来看这两个题目,其实求解的东西一样,不同在于,第一个问题是新建一个排序好的新数组,而第二题是将一个数组合并到另一个数组中去。怎样做呢?两个题的基本思路都一样:通过两个指针同时扫描两个数组。


先来看第一题,我们通过设置两个指针(此处就用数组元素的下标来表示)分别扫描A,B。同时,在开始阶段建立一个新的空数组result=[],作为结果输出。扫描过程中,不断将数组元素按照下列规则“push”进result:
(1)如果A[i] > B[j],将B[j]压入result,同时令j = j + 1(扫描B的指针向后移一位)
(2)如果A[i] < B[j],将A[i]压入result,同时令i=i+ 1(与上步做法一致)
(3)如果其中一个数组扫描完了,而另一个还没完,那么将没扫描完的数组的剩余部分全部压入result
因为A,B都是排好序的,所以通过以上规则,我们可以得到合并后的,排好序的数组result。


Python代码如下:

class Solution:    #@param A and B: sorted integer array A and B.    #@return: A new sorted integer array    def mergeSortedArray(self, A, B):        nA = len(A)        nB = len(B)        result = []        index_A = index_B = 0        # 两个指针都不能越界        while index_A != nA and index_B != nB:            if A[index_A] < B[index_B]:                result.append(A[index_A])                index_A += 1            else:                result.append(B[index_B])                index_B += 1        # 与未被扫描的部分合并,因为都是排好序的数组,所以直接相加        result += A[index_A:]        result += B[index_B:]        return result        # write your code here

这个还是很容易理解的。如果这道题没问题了,就可以看第二个问题,要求把两个数组合并成一个,而且给出了两个数组非空元素的数目:m,n。首先想这样一个问题,两个数组合并后的非空元素个数一定是m+n。也就是说,如果输出的结果数组(题中的意思就是A了)是这种形式:[*,*,*,*, empty, empty...empty]的话(*表示非空元素),那么最后一个非空元素的下标为m+n-1(下标从0开始)。那就可以考虑分别设两个指针从后往前扫描A,B数组,并且从A[m+n-1]这个位置开始,再设置一个指针,从后往前给A的元素重新赋值。扫描的规则与第一题同理,不同在于因为是从后往前扫描,所以按照“谁大谁先赋值”的规则,举题目的例子如下:


A = [1, 2, 3, empty, empty] 
B = [4,5]
m = 3
n = 2
m + n - 1 = 4
所以,从A[4]这个位置,向前开始赋值:
(1)先比较A[2] = 3和B[1] = 5,因为B[1] > A[2],所以令A[4] = B[1] = 5
(2)比较B[0]和A[2],大者赋值给A[3]
(3)按照这个规则持续扫描,直到其中一个扫描完为止


可见,之所以采取从后往前,而不是从前往后,是为了避免大量元素移位造成的运算量。


但是,接下来,我们要分析这么个事:其中一个扫描完了怎么办?
如果是A先扫描完,可以想象,情况是这样:假如A = [4, 5, empty, empty, empty],B = [1, 2, 6],A一定先扫描完,此时A = [4, 5, 4, 5, 6],B = [1, 2, 6],那么须要将B的剩余部分[1, 2]分别赋值给A的还没赋值的部分;
而如果是B先扫描完了,那情况就简单了,我们不需任何操作(因为A前面没有扫描的部分也是排好序的)。


直接看代码吧,也许就能理解了:


class Solution:    """    @param A: sorted integer array A which has m elements,               but size of A is m+n    @param B: sorted integer array B which has n elements    @return: void    """    def mergeSortedArray(self, A, m, B, n):        # 实际上用m,n,total代表三个指针        total = m + n        while m > 0 and n > 0:            if A[m - 1] > B[n - 1]:                A[total - 1] = A[m - 1]                m -= 1            else:                A[total - 1] = B[n - 1]                n -= 1            total -= 1        # 如果是B没扫描完,依次对未赋值的A元素赋值        while n > 0:            A[total - 1] = B[n - 1]            n -= 1            total -= 1        return A        # write your code here

其实很简单的,我觉得反倒是让我说复杂了,没办法,表达能力实在有限。。。那么问题来了,为什么在这里讲了两道lintcode的题呢,是为了下一节归并排序做准备。



0 0