尝试将3个数组合并为一个,以便最终数组按顺序排列。
给出
int[] a = {1,3};
int[] b = {2,4};
int[] c = {1,5};
合并数组,使最终数组d = {1,1,2,3,4,5}
不能连接它们然后对d数组进行排序,因为这会使时间复杂度大于Big-O(N)。
这是我到目前为止所得到的。索引超出限制异常时遇到问题:
public static void main(String[] args) {
// Sort these 3 arrays. The final array should be d = {1,1,2,3,4,5}
int[] a = {1,3};
int[] b = {2,4};
int[] c = {1,5};
int[] d = new int[a.length + b.length + c.length];
int i = 0;
int j = 0;
int k = 0;
int l = 0;
for (int iteration = 0; iteration <= d.length; iteration++){
if ((i != a.length || j != b.length) && a[i] < b[j]){
if (a[i] < c[k]){
// then a[i] is smallest
d[l] = a[i];
i++;
l++;
displayArrayContents(a,b,c,d,i,j,k,l);
}
else if (a[i] > c[k]){
// then c[k] is smallest
d[l] = c[k];
k++;
l++;
displayArrayContents(a,b,c,d,i,j,k,l);
}
else if (a[i] == c[k]){
d[l] = a[i];
i++;
l++;
d[l] = c[k];
k++;
l++;
displayArrayContents(a,b,c,d,i,j,k,l);
}
}
else if(b[j] < a[i]){
if (b[j] < c[k]){
// b[j] is smallest
d[l] = b[j];
l++;
j++;
displayArrayContents(a,b,c,d,i,j,k,l);
}
else if (b[j] > c[k]){
// c[k] is smallest
d[l] = c[k];
l++;
k++;
displayArrayContents(a,b,c,d,i,j,k,l);
}
else if (b[j] == c[k]){
d[l] = b[j];
j++;
l++;
d[l] = c[k];
k++;
l++;
displayArrayContents(a,b,c,d,i,j,k,l);
}
}
}
}
答案 0 :(得分:4)
您的想法是正确的,代表 O(n)解决方案。但是,您的代码确实存在一些问题,其中一些问题会导致越界异常:
c[k]
; k < c.length
length
上进行测试,也是以无法避免此类无效访问的方式执行此操作:(i != a.length || j != b.length) && a[i] < b[j]
仍会导致a[i]
在i === a.length
(特别是j != b.length
); a[i] == c[k]
)并不需要单独处理。如果将它与>
一起处理(所以:>=
),算法仍然正确:第二个(相等)值将在下一次迭代中复制; for
条件应为< d.length
而非<= d.length
没有问题,但您的代码中有很多重复:
displayArrayContents(a,b,c,d,i,j,k,l);
构造之外的if
,因此它总是被执行,这是你真正想要的; d
构造中分配给if
,因此您可以使用三元运算符if
将该分配置于“? ... :
”之外; i != a.length
这样的测试可以达到预期目的,但最好是按照以下方式进行测试:i < a.length
。 以下是考虑到上述代码的代码:
import java.util.Arrays; // for easy output of arrays with Arrays.toString().
class Main {
public static void main(String[] args) {
// Sort these 3 arrays. The final array should be d = {1,1,2,3,4,5}
int[] a = {1,3};
int[] b = {2,4};
int[] c = {1,5};
int[] d = new int[a.length + b.length + c.length];
int i = 0;
int j = 0;
int k = 0;
for (int l = 0; l < d.length; l++) {
d[l] = i < a.length && (j >= b.length || a[i] < b[j])
? (k >= c.length || a[i] < c[k]
? a[i++]
: c[k++])
: (j < b.length && (k >= c.length || b[j] < c[k])
? b[j++]
: c[k++]);
// Uncomment this if you still need it:
//displayArrayContents(a,b,c,d,i,j,k,l);
}
System.out.println(Arrays.toString(d));
}
}
最后一项陈述的输出:
[1, 1, 2, 3, 4, 5]
在repl.it上看到它。
答案 1 :(得分:2)
请按照以下步骤操作:
a
和b
上调用该函数,以获取生成的数组ab
ab
和c
上调用该功能,以获得结果abc
O(n)
函数,因此它仍然是O(n)
。 BOOM。事实是,玩数组索引令人沮丧。如果您可以将这些数组替换为队列或Itererator,只需take()
或next()
每次迭代中的最小值并将其放在结果列表中,它就会更清晰。
答案 2 :(得分:0)
你需要清楚N的变化。如果你总是只有三个数组,它们的大小或最大大小随N变化,那么几乎所有重复选择三个数组中任何一个数组的代码的代码,删除它,并将其追加到结果数组的末尾,将是O(N)。您选择最小数字的代码可能很笨拙而且价格昂贵,但它只是一个不变因素,随着N的增加不会改变。
如果要合并的数组数量随N增加,那么您需要更加小心选择可用的最小数字,最终会出现排序问题,在线性时间内无法做到通常的假设。
通常,外部排序会使用堆(例如http://www.geeksforgeeks.org/external-sorting/)合并磁盘上保存的大量列表。这对于一次合并大量列表会更有效,但只是为了获得一个常数因子,
答案 3 :(得分:0)
假设这是java,数组名称是对数组的引用,可以像C / C ++中的指针一样交换。这可以用于减少主合并循环中的条件数量,使代码更简单,但代价是交换。在主合并循环之前完成空数组检查。这种方法可以很容易地扩展到处理4路或更大的合并,否则需要很多条件。
static int[] Merge(int[] a, int[] b, int[] c)
{
int[] d = new int[a.length + b.length + c.length];
int[] e; // temp used for swap
int i = 0;
int j = 0;
int k = 0;
int l = 0;
int t;
// empty array checks
if(0 == b.length){ // if b empty
if(0 == c.length){ // if b and c empty
c = a; // c = a
a = b; // a = b = empty
} else { // if b empty, c not empty
e = a; // swap a and b
a = b;
b = e;
}
} else { // else b not empty
if(0 == c.length){ // if c empty
e = c;
c = b; // shift c = b, b = a
b = a;
a = e; // a = empty
}
}
// main merge loop
while(i < a.length){ // 3 way merge
if(a[i] > b[j]){ // if b smaller swap
e = a;
a = b;
b = e;
t = i;
i = j;
j = t;
}
if(a[i] > c[k]){ // if c smaller swap
e = a;
a = c;
c = e;
t = i;
i = k;
k = t;
}
d[l++] = a[i++];
}
while(j < b.length){ // 2 way merge
if(b[j] > c[k]){ // if c smaller swap
e = b;
b = c;
c = e;
t = j;
j = k;
k = t;
}
d[l++] = b[j++];
}
while(k < c.length) // copy rest of c
d[l++] = c[k++];
return d;
}