Beh*_*joo 157 java algorithm big-o mergesort
我在接受采访时被问及这是我提供的解决方案:
public static int[] merge(int[] a, int[] b) {
    int[] answer = new int[a.length + b.length];
    int i = 0, j = 0, k = 0;
    while (i < a.length && j < b.length)
    {
        if (a[i] < b[j])
        {
            answer[k] = a[i];
            i++;
        }
        else
        {
            answer[k] = b[j];
            j++;
        }
        k++;
    }
    while (i < a.length)
    {
        answer[k] = a[i];
        i++;
        k++;
    }
    while (j < b.length)
    {
        answer[k] = b[j];
        j++;
        k++;
    }
    return answer;
}
有没有更有效的方法来做到这一点?
编辑:更正长度方法.
Mik*_*ull 107
public static int[] merge(int[] a, int[] b) {
    int[] answer = new int[a.length + b.length];
    int i = 0, j = 0, k = 0;
    while (i < a.length && j < b.length)  
       answer[k++] = a[i] < b[j] ? a[i++] :  b[j++];
    while (i < a.length)  
        answer[k++] = a[i++];
    while (j < b.length)    
        answer[k++] = b[j++];
    return answer;
}
有点紧凑,但完全一样!
Shi*_*hah 54
我很惊讶没有人提到这个更酷,更有效和紧凑的实现:
public static int[] merge(int[] a, int[] b) {
    int[] answer = new int[a.length + b.length];
    int i = a.length - 1, j = b.length - 1, k = answer.length;
    while (k > 0)
        answer[--k] =
                (j < 0 || (i >= 0 && a[i] >= b[j])) ? a[i--] : b[j--];
    return answer;
}
兴趣点
System.arraycopy将获胜,因为在内部它可以使用单个x86汇编指令执行此操作.a[i] >= b[j]而不是a[i] > b[j].这保证了"稳定性",定义为当a和b的元素相等时,我们想要来自b之前的元素.小智 10
此解决方案也非常类似于其他帖子,除了它使用System.arrayCopy复制其余的数组元素.
private static int[] sortedArrayMerge(int a[], int b[]) {
    int result[] = new int[a.length +b.length];
    int i =0; int j = 0;int k = 0;
    while(i<a.length && j <b.length) {
        if(a[i]<b[j]) {
            result[k++] = a[i];
            i++;
        } else {
            result[k++] = b[j];
            j++;
        }
    }
    System.arraycopy(a, i, result, k, (a.length -i));
    System.arraycopy(b, j, result, k, (b.length -j));
    return result;
}
这是更新的功能.它删除重复,希望有人会发现这可用:
public static long[] merge2SortedAndRemoveDublicates(long[] a, long[] b) {
    long[] answer = new long[a.length + b.length];
    int i = 0, j = 0, k = 0;
    long tmp;
    while (i < a.length && j < b.length) {
        tmp = a[i] < b[j] ? a[i++] : b[j++];
        for ( ; i < a.length && a[i] == tmp; i++);
        for ( ; j < b.length && b[j] == tmp; j++);
        answer[k++] = tmp;
    }
    while (i < a.length) {
        tmp = a[i++];
        for ( ; i < a.length && a[i] == tmp; i++);
        answer[k++] = tmp;
    }
    while (j < b.length) {
        tmp = b[j++];
        for ( ; j < b.length && b[j] == tmp; j++);
        answer[k++] = tmp;
    }
    return Arrays.copyOf(answer, k);
}
小智 5
它可以在4个语句中完成,如下所示
 int a[] = {10, 20, 30};
 int b[]= {9, 14, 11};
 int res[]=new int[a.legth+b.length]; 
 System.arraycopy(a,0, res, 0, a.length); 
 System.arraycopy(b,0,res,a.length, b.length);
 Array.sort(res)
我继续在评论中实施了灰胡子的建议。主要是因为我需要此代码的高效关键任务版本。
这应该是最有效的方法,时间复杂度为O(log(n)*log(i))而不是 O(n)。最坏情况时间复杂度为 O(n)。如果你的数组是块状的并且有很长的值串在一起,这将使任何其他方法相形见绌,否则它只会比它们更好。
它在合并数组的末尾有两个读取值,在结果数组中有写入值。在找出哪个最终值较小后,它会对该数组进行快速搜索。1, 2, 4, 8, 16, 32 等。当它找到另一个数组的读取值较大的范围时。它二进制搜索到该范围内(将范围减半,搜索正确的一半,重复直到单个值)。然后它数组将这些值复制到写入位置。请记住,副本必须移动,以便它不能覆盖任一读取数组中的相同值(这意味着写入数组和读取数组可以相同)。然后它对另一个数组执行相同的操作,该数组现在已知小于另一个数组的新读取值。
static public int gallopSearch(int current, int[] array, int v) {
    int d = 1;
    int seek = current - d;
    int prevIteration = seek;
    while (seek > 0) {
        if (Integer.compare(array[seek], v) <= 0) {
            break;
        }
        prevIteration = seek;
        d <<= 1;
        seek = current - d;
        if (seek < 0) {
            seek = 0;
        }
    }
    if (prevIteration != seek) {
        seek = binarySearch(array, seek, prevIteration, v);
        seek = seek >= 0 ? seek : ~seek;
    }
    return seek;
}
static public int binarySearch(int[] list, int fromIndex, int toIndex, int v) {
    int low = fromIndex;
    int high = toIndex - 1;
    while (low <= high) {
        int mid = (low + high) >>> 1;
        int midVal = list[mid];
        int cmp = Integer.compare(midVal, v);
        if (cmp < 0) {
            low = mid + 1;
        } else if (cmp > 0) {
            high = mid - 1;
        } else {
            return mid;// key found
        }
    }
    return -(low + 1);// key not found.
}
static public int[] sortedArrayMerge(int[] a, int[] b) {
    return sortedArrayMerge(null, a, a.length, b, b.length);
}
static public int[] sortedArrayMerge(int[] results, int[] a, int aRead, int b[], int bRead) {
    int write = aRead + bRead, length, gallopPos;
    if ((results == null) || (results.length < write)) {
        results = new int[write];
    }
    if (aRead > 0 && bRead > 0) {
        int c = Integer.compare(a[aRead - 1], b[bRead - 1]);
        while (aRead > 0 && bRead > 0) {
            switch (c) {
                default:
                    gallopPos = gallopSearch(aRead, a, b[bRead-1]);
                    length = (aRead - gallopPos);
                    write -= length;
                    aRead = gallopPos;
                    System.arraycopy(a, gallopPos--, results, write, length);
                    c = -1;
                    break;
                case -1:
                    gallopPos = gallopSearch(bRead, b, a[aRead-1]);
                    length = (bRead - gallopPos);
                    write -= length;
                    bRead = gallopPos;
                    System.arraycopy(b, gallopPos--, results, write, length);
                    c = 1;
                    break;
            }
        }
    }
    if (bRead > 0) {
        if (b != results) {
            System.arraycopy(b, 0, results, 0, bRead);
        }
    } else if (aRead > 0) {
        if (a != results) {
            System.arraycopy(a, 0, results, 0, aRead);
        }
    }
    return results;
}
这应该是最有效的方法。
一些答案具有重复删除功能。这将需要 O(n) 算法,因为您必须实际比较每个项目。所以这是一个独立的,在事后应用。如果您需要查看所有条目,则无法一路浏览多个条目,但如果您有很多重复项,则可以浏览重复项。
static public int removeDuplicates(int[] list, int size) {
    int write = 1;
    for (int read = 1; read < size; read++) {
        if (list[read] == list[read - 1]) {
            continue;
        }
        list[write++] = list[read];
    }
    return write;
}
更新:以前的答案,不是可怕的代码,但明显不如上面的。
另一个不必要的超优化。它不仅为结束位调用 arraycopy,还为开头调用。通过二进制搜索将 O(log(n)) 中的任何介绍性非重叠处理到数据中。O(log(n) + n) 是 O(n) 并且在某些情况下效果会非常明显,尤其是在合并数组之间根本没有重叠的情况下。
private static int binarySearch(int[] array, int low, int high, int v) {
    high = high - 1;
    while (low <= high) {
        int mid = (low + high) >>> 1;
        int midVal = array[mid];
        if (midVal > v)
            low = mid + 1;
        else if (midVal < v)
            high = mid - 1;
        else
            return mid; // key found
    }
    return low;//traditionally, -(low + 1);  // key not found.
}
private static int[] sortedArrayMerge(int a[], int b[]) {
    int result[] = new int[a.length + b.length];
    int k, i = 0, j = 0;
    if (a[0] > b[0]) {
        k = i = binarySearch(b, 0, b.length, a[0]);
        System.arraycopy(b, 0, result, 0, i);
    } else {
        k = j = binarySearch(a, 0, a.length, b[0]);
        System.arraycopy(a, 0, result, 0, j);
    }
    while (i < a.length && j < b.length) {
        result[k++] = (a[i] < b[j]) ? a[i++] : b[j++];
    }
    if (j < b.length) {
        System.arraycopy(b, j, result, k, (b.length - j));
    } else {
        System.arraycopy(a, i, result, k, (a.length - i));
    }
    return result;
}