leetcode 88.合并两个有序数组

leetcode 88.合并两个有序数组

题目描述

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3
输出: [1,2,2,3,5,6]

解法一

因为数组1的总长度是大于等于m+n的,所以把数组2的元素都拷贝到数组1中。
数组1中的元素有m个,所以数组2中的第一个元素拷贝到数组1中对应的下标就是m
第二个元素拷贝过来对应的下标是m+1
一直到m+n-1
拷贝完后,将数组1整体排序一遍就搞定了,这里没有用到外部空间,但排序一遍最快也要 O((n+m)log(n+m))时间,所以时间复杂度会略高

java代码:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        for(int i=m,j=0;i<n+m;++i,++j) {
            nums1[i] = nums2[j];
        }
        Arrays.sort(nums1);
    }
}

python代码:

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        j = 0
        for i in xrange(m,m+n):
            nums1[i] = nums2[j]
            j += 1
        nums1.sort()
                                           

解法二

跟合并两个有序链表类似,这里也用两个指针分别指向数组1的开头,和数组2的开头。
跟链表合并不同,如果往数组中插入一个元素,为了保证整体的顺序性,需要挪动前后的元素,所以我们需要再新建一个数组。
之后比较两个数组中的元素nums1[i]nums2[j],将其放到新数组中。

这种两两合并的好处是可以免掉排序了,比较完之后再放到新数组中,元素都是有序的了。
但题目要求是在数组1的基础上进行修改,而不是返回一个新数组,所以我们还得把排序好的新数组内容,再重新赋给数组1。

java代码:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = 0;
        int j = 0;
        int k = 0;
        int[] arr = new int[n+m];
        while(j<m || k<n) {
            //注意两个边界条件:j==m,以及k==n,表示一个数组已经拷贝完了
            if(j==m) {
                arr[i++] = nums2[k++];
            }
            else if(k==n) {
                arr[i++] = nums1[j++];
            }
            else if(nums1[j]<=nums2[k]) {
                arr[i++] = nums1[j++];
            }
            else {
                arr[i++] = nums2[k++];
            }
        }
        //还需要将新数组中的元素再拷贝回去
        for(i=0;i<arr.length;++i) {
            nums1[i] = arr[i];
        }
    }
}
                                                                        

python代码:

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        arr = [0 for _ in xrange(n+m)]
        i = 0
        j = 0
        k = 0
        while j<m or k<n:
            # 注意两个边界条件:j==m,以及k==n,表示一个数组已经拷贝完了
            if j==m:
                arr[i] = nums2[k]
                k += 1
            elif k==n:
                arr[i] = nums1[j]
                j += 1
            elif nums1[j]<=nums2[k]:
                arr[i] = nums1[j]
                j += 1
            else:
                arr[i] = nums2[k]
                k += 1
            i += 1
        # 还需要将新数组中的元素再拷贝回去 
        for i in xrange(len(arr)):
            nums1[i] = arr[i]
                                                                          

解法三

解法二中我们将两个数组合并到一个新数组中,是从两个数组的开头开始一一比较。
这是符合直觉的,但仔细想想,数组1和数组2都是有序的,所以从前往后看是有序,从后往前看也是有序。
另外题目中也说明了,数组1的空间是足够的,它可以完全容纳下数组1的m个元素和数组2的n个元素。
这两个条件拼在一起,我们就有了新的比较方式,即:反着比较。

我们反着比较nums1[m-1]nums2[n-1],因为6更大所以将6拷贝过去。
注意,这回我们不用再新建一个数组了,数组1后面都是空着的,也有足够空间可以容纳下数组2中的所有元素。
我们将两个数组中最大的数放到数组1的最后一位(下标n+m-1处),将倒数第二大的数放到数组1的倒数第二位(下标n+m-2处)。
依次类推直到两个数组的元素全部比较完。
最后数组1就是有序的,这种比较方式不需要再占用额外的空间。

java代码:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m-1;
        int j = n-1;
        int k = m+n-1;
        while(i>=0 || j>=0) {
            //注意两个边界条件,i<0以及j<0,这表示一个数组已经拷贝完了
            if(i<0) {
                nums1[k--] = nums2[j--];
            }
            else if(j<0) {
                nums1[k--] = nums1[i--];
            }
            //反向比较时,拷贝的是较大的那个元素
            else if(nums1[i]<=nums2[j]) {
                nums1[k--] = nums2[j--];
            }
            else {
                nums1[k--] = nums1[i--];
            }
        }
    }
}
                                                                        

python代码:

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        i = m-1
        j = n-1
        k = m+n-1
        while i>=0 or j>=0:
            # 注意两个边界条件,i<0以及j<0,这表示一个数组已经拷贝完了
            if i<0:
                nums1[k] = nums2[j]
                j -= 1
            elif j<0:
                nums1[k] = nums1[i]
                i -= 1
            # 反向比较时,拷贝的是较大的那个元素 
            elif nums1[i]<=nums2[j]:
                nums1[k] = nums2[j]
                j -= 1
            else:
                nums1[k] = nums1[i]
                i -= 1
            k -= 1
                                                                         

(全文完)

1 次阅读

发表评论

电子邮件地址不会被公开。