[这是一个面试问题。我找不到重复的内容。]
数组包含两个子排序数组。给出一个inplace算法来排序两个子数组。
代表:I / P:1 4 5 7 8 9 2 3 6 10 11 O / P:1 2 3 4 5 6 7 8 9 10 11
我认为在就地合并排序,插入排序(因为子数组已经排序)和快速排序方面但是无法想到一个比使用标准排序更复杂的解决方案方法
请帮我找一个算法,它允许我们利用排序的子数组属性,并且比在输入上运行Quicksort时产生更好的时间复杂性。
这是我想到的合并排序模拟,使用这个例子:
1) For position 0, Comparing 1 & 2, 1 is smaller let it stay at it's original place
2) For position 1, Comparing 2 & 4, 2 is smaller so swap 2 and 4
3) For position 2, Comparison now is between 4 and 3 (5 > 4 anyways) swap 3 and 5
4) For position 3, Comparison between 4 & 5, swap 4 and 7
5) For position 4, Comparison between 7 & 5, swap 8 and 5
6) For position 5, Comparison between 7 & 8 (OUCH!!) it should have been between 7 & 6
似乎这个问题类似于排序矩阵的排序行,其中就地合并太复杂了。
答案 0 :(得分:6)
有关解决此问题的线性时间算法,请参阅http://comjnl.oxfordjournals.org/content/38/8/681.full.pdf+html,并说明该解决方案花费了多少精力。
我的猜测是,面试官有一些他们认为有用的可爱答案,但事实并非如此。第二个最好的猜测是他们没有指出复杂性的原因。
在一次采访中我实际上会说,“我不知道如何有效地做到这一点,虽然我确信有关于这个问题的研究。但这是一个效率低下的答案。”然后我会做一些明显有用的事情。
答案 1 :(得分:4)
有一个就地合并排序具有O(n log n)最坏情况的行为,但正如文章所说,“由于所涉及的常数因素,算法主要是理论上的兴趣。”见https://stackoverflow.com/a/2571104/56778
如果你不能分配一个与排序的子阵列一样大的临时缓冲区,则就地合并非常困难。
答案 2 :(得分:0)
对于面试问题,在您的算法中,一旦交换,结果数组就不再单独排序了。你应该向更大的交换元素“冒泡”,直到它到达正确的位置,然后继续。
为了简单起见,我们采用2个数组,topA和topB作为当前位置(最初都是0)。令所需的结果数组为A [1..m] .. B [1..n]。这是一个伪代码:
if (A[topA] < B[topB]) {
swap (A[topA], B[topB])
index = topB;
while (B[index] < B[index + 1]) {
swap(B[index], B[index + 1])
}
topB++
} else {
topA++;
}
在上述每次运行结束时,结果数组被分类并且更小。这可以继续,直到其中一个阵列用完。然而,由于起泡阶段,复杂性将大于O(m + n)。
答案 3 :(得分:0)
// since both are sorted use array b as min heap
// if a[i] > b[0] (top of min-heap), exch it and heapify b
// order : O(nlog(n))
void inplaceMerge(vector<int>& a, vector<int>& b)
{
for (int i=0; i < a.size(); i++) {
if (a[i] > b[0]) {
swap(a[i], b[0]);
sink(b, 0, b.size()-1); // bubbleDown() operation in heap()
}
}
sort(b.begin(), b.end());
}
void sink(vector<int>& b, int i, int n)
{
int j = 2*i + 1;
while (j <= n) {
if (j+1 < n && b[j+1] < b[j]) j++;
if (b[j] < b[i]) swap(b[i], b[j]);
else break;
i = j;
j = 2*i + 1;
}
}