lintcode练习- 64. 合并排序数组,65. 合并排序数组II

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


这个还是很容易理解的。如果这道题没问题了,就可以看第二个问题,要求把两个数组合并成一个,而且给出了两个数组非空元素的数目: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: m: An integer
    @param: B: sorted integer array B which has n elements
    @param: n: An integer
    @return: nothing
    """
    def mergeSortedArray(self, A, m, B, n):
        # write your code here
        total = m+n-1
        while m > 0 and n > 0:
            if A[m-1] > B[n-1]:
                A[total] = A[m-1]
                m -= 1
            else:
                A[total] = B[n-1]
                n -= 1
            
            total -= 1
        #如果B没有扫描完,就将剩余的B全部放在A的前面
        if n > 0:
            A[:total+1] = B[:n]
        
        return A
        
        
                


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

猜你喜欢

转载自blog.csdn.net/qq_36387683/article/details/82455421