算法之---合并有序数组

前言

在工作中我们会经常使用数组这个数据结构,其中会碰到需要合并数组的且使之有序的需求,一般经过查询(数据库排序)返回的结果大多数都是有序数组,那么如何将多个数组进行合并呢?
其实无论是两个还是多个数组,本质上都可以利用数组的两两合并。

实现方式

排序法

我们大可以直接直接合并两个或者多个数组,不用考虑其顺序,然后再使用排序即可,在Java里甚至可以使用集合的addAll和sort方法,仅需两行代码就可以搞定,接下来让我们分析一下,假设总元素个数为n且使用快速排序,那么需要O(nlogn)的时间复杂度,以及快排所需的O(logn)空间复杂度。

移位法

如果数组1足够长,为了不利用新的数组空间,我们可以从头开始遍历两个数组将小的插入到数组1中并将数组1中的所有元素后移一位即可

public void merge(int[] nums1, int m, int[] nums2, int n) {
        int size = m ,i = 0, j = 0;
        for(i = 0,j = 0; i<size&&j<n; i++){
            if(nums1[i]>nums2[j]){
                size++;
                for(int k = size-1; k>i; k--){
                    nums1[k]=nums1[k-1];
                }
                nums1[i] = nums2[j];
            
                j++;
            }
            
        }
       
        for(int k = j; k<n; k++){
            nums1[m+k] = nums2[k];
        }
       

    }

最坏的时间复杂度为O(n^2),空间复杂度为O(1)

双指针

排序法没有利用数组有序这一特性,我们可以考虑新建一个长度为n的数组,然后将数组1和数组2,分别从头开始比较,元素较小的进入新数组,并是原数组的索引加1,直至最后,再将剩余的元素直接放入新数组尾部即可,代码如下:

public void merge(int[] nums1, int m, int[] nums2, int n) {
        int index1 = 0, index2 = 0;
        int[] sorted = new int[m + n];
        int min;
        while (index1 < m || index1 < n) {
            if (p1 >= m) {
                min= nums2[index2++];
            } else if (p2 >= n) {
                min= nums1[index1++];
            } else if (nums1[index1] < nums2[index2]) {
                min= nums1[index1++];
            } else {
                min= nums2[index2++];
            }
            sorted[index1 + index2 - 1] = cur;
        }
}

当某个数组达到边界时,我们可以认为其实无穷大的,这样另外一个数组剩余的元素就会自动进入新数组,时间和空间复杂度均为O(n)

逆向双指针

上述方式我们利用数组是有序的特点,但是如果给出的数组1本身可以容纳所有元素时,我们不妨从两个数组的尾部进行比较,假设num1含有m元素,num2含有n个元素,且num1数组的容量是m+n时,我们可以直接将合并后的元素放到num1中而不是新建一个长度为n的数组,此时我们只需要避免在插入到num1时避免将其本来的元素覆盖即可,这个时候就可以利用num1尾部是空的特性,分别从两个元素的最后一个元素开始比较,将较大的元素放到num1的尾部就可以实现

public void merge(int[] nums1, int m, int[] nums2, int n) {
        int index1 = m - 1, index2 = n - 1;
        int tail = m + n - 1;
        int max;
        while (index1>= 0 || index2>= 0) {
            if (index1<= -1) {
                max= nums2[index2--];
            } else if (index2<= -1) {
                max= nums1[index1--];
            } else if (nums1[index1] > nums2[index2]) {
                max= nums1[index1--];
            } else {
                max= nums2[index2--];
            }
            nums1[tail--] = max;
        }
}

同理,当索引为-1时说明该数组已经遍历结束,为了将另外一个数组的元素继续放到nums1中,我们认为遍历结束的数组为无穷小即可,此时空间复杂度为O(1),时间为O(m+n)

结束语

不定期更新算法结题方法,有更好的方法欢迎指导~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值