将两个升序数组合并成一个新的升序数组

晚上突然接到朋友一个灵魂拷问,如何把将两个升序数组 a[] 和 b[] 合并成一个升序数组 c[]

第一反应就是把两个数组按位拷贝到一个新的数组中,再排序不就完事了嘛,要什么效率能跑就行。但是那一天,我终于回想起曾经一度被面试官支配的恐惧,以及还在做码农搬砖的屈辱。我想起了写下第一行代码的时候,天空是那么蓝,理想是那么丰满,啊,不好意思扯远了。

其实这个题目的解法思路非常简单,但是设计起来就很费力。

我的基本思路就是创建一个新的数组,通过‘对撞指针’(我开始并不知道,我只知道从两端同时处理会更高效一点)对数组进行遍历式的存放,即两个源数组从头部(index为0)和尾部(index为数组长度-1)同时进行比较,比较的结果存放到目标数组对应的下标位置中,同时移动对应源数组的指针和目标数组的指针,直到目标数组左右指针交叉,计算完成。

我的代码实现如下,特此记录,以免将来自己都忘记了当初自己是怎么做的,毕竟灵感就像是放屁一样,指不定什么时候就蹦出来一个

i1: 数组arr1的头部指针

k1: 数组arr1的尾部指针

i2: 数组arr2的头部指针

k2: 数组arr2的尾部指针

i3: 目标数组arr3的头部指针

k3:目标数组arr3的尾部指针

m1:  一个标记,从前到后放入到目标数组中的元素是否是arr1中的元素,如果是,则表示要移动arr1的指针,否则移动arr2的,index+1

m2: 一个标记,从后往前放入目标数组中的元素是否是arr1中的元素,如果是,则表示要移动arr1的指针,否则移动arr2的,index-1

 

上面有个bug,两个数组中的某一个中,分布的元素数值过于大或者过于小,且元素个数很小,会让我们设置的指针一直单向偏移,最终造成数组下标越界的风险。如果左右指针只要有一个达到数组的边界,就说明这个数组已经全部合并到目标数组中去了,接下来就只要把空间让另一个源数组的剩余元素填充就行了。2021-07-30晚上更新如下:

private static int[] simpleMerge(int[] arr1, int[] arr2) {
    int n1 = arr1.length;
    int n2 = arr2.length;
    int n3 = n1 + n2;
    int[] arr3 = new int[n1 + n2];
    boolean m1, m2;
    int i1 = 0, i2 = 0, i3 = 0, k1 = n1 - 1, k2 = n2 - 1, k3 = n3 - 1;
    while (true) {
        if (i3 > k3) { break; }
        if (i1 > n1 - 1 || k1 < 0) {
            arr3[i3] = arr2[i2];
            arr3[k3] = arr2[k2];
            m1 = false;
            m2 = false;
        } else if (i2 > n2 - 1 || k2 < 0) {
            arr3[i3] = arr1[i1];
            arr3[k3] = arr1[k1];
            m1 = true;
            m2 = true;
        } else {
            m1 = arr1[i1] > arr2[i2] ? (arr3[i3] = arr2[i2]) == arr1[i1] : (arr3[i3] = arr1[i1]) == arr1[i1];
            m2 = arr1[k1] > arr2[k2] ? (arr3[k3] = arr1[k1]) == arr1[k1] : (arr3[k3] = arr2[k2]) == arr1[k1];
        }
        if (m1) { i1++; } else { i2++; }
        if (m2) { k1--; } else { k2--; }
        i3++;
        k3--;

    }
    return arr3;
}

 

posted @ 2021-07-30 20:31  爆炸橙子  阅读(1803)  评论(0编辑  收藏  举报