我有两个未排序的数组a
和b
。对于每个元素a[i]
,我需要找到b[j]
元素的数量b[j] < a[i]
。此外,b
可能包含不应计算的重复项。两个阵列都可能非常大。
我尝试过(针对单个查询x
)
public static void main(String arg[]) {
int x = 5;
int b[] = {2, 4, 3, 4, 11, 13, 17};
Arrays.sort(b);
int count = 0;
for(int i = 0; i < b.length; ++i) {
if(b[i] < x) {
if(i == 0)
++count;
else {
// this check avoids counting duplicates
if(b[i - 1] != b[i])
++count;
}
} else {
break;
}
}
System.out.println(count);
}
我的问题是,当迭代地查询a
的所有元素时,这不能很好地执行。我该怎么做才能加快速度呢?
答案 0 :(得分:5)
编辑:鉴于后面的评论,我刚刚在开始时提出了一些更新;将我的第一个文字留在底部。
所以,这里的核心方面是:
好的,关于你的问题。事情是:实际上,这只是&#34;工作&#34;。那里没有魔力。由于您有两个非常大的数组,处理未排序的数据是绝对禁止的。
因此,您首先要对两个数组进行排序。
然后迭代第一个数组,同时这样做,你也会查看第二个数组:
int indexWithinB = 0;
int counterForCurrentA = 0; // and actually ALL values from a before
for (int i=0; i<a.length; i++) {
int currentA = a[i];
while (b[indexWithinB] < currentA) {
if (indexWithinB > 0) { // check required to avoid using 0-1
if (b[indexWithinB-1] != b[indexWithinB] { // avoid counting duplicates!
counterForCurrentA++;
}
}
indexWithinB++;
}
// while loop ended, this means: b[indexWithinB] == or > currentA
// this also means: counterForCurrentA ... should have the correct value
}
以上显然是伪代码。它旨在让你继续前进;而且很可能是那里存在微妙的错误。例如,正如安德烈亚斯指出的那样:上面需要加强以检查b.length。但这仍然是读者的锻炼。
这就是我的意思&#34;只是工作&#34;:您只需坐下来,编写测试用例并优化我的草案算法,直到它为您完成工作。如果你发现它最初很难编程,那么拿一张纸,放下两个带数字的数组......然后手动计算。
最后提示:我建议编写大量的单元测试来测试你的算法(这样的东西完美用于单元测试);并确保你在这些测试中拥有所有的角落案例。在进入10 ^ 5元素阵列之前,您希望100%确定您的算法是正确的!
在这里,正如所承诺的那样,原来的答案是:
简单地说:迭代和计数是解决此问题的最有效方法。因此,在上述情况下,省略排序可能会缩短整体执行时间。
逻辑非常简单:为了知道小于x的数字的数量......你必须看看所有。因此,您必须迭代整个数组(当该数组未排序时)。
因此,鉴于您的初始陈述,除了:迭代和计数之外没有别的东西。
当然,如果您需要多次计算......最初可能值得对数据进行排序。因为那时你可以使用 binary search ,并且在没有迭代所有数据的情况下获得那些数量。
并且:是什么让你认为用10 ^ 5元素迭代一个数组是个问题?换句话说:您是否只是担心潜在的性能问题,或者您是否存在真正的性能问题?你看,在某些时候你可能不得不创建和填充那个数组。这肯定比简单的for循环计数条目需要更多的时间(和资源)。老实说:除非我们正在谈论一些小型嵌入式设备...... 10 ^ 5个元素......即使在使用稍微过时的硬件时,几乎没有。
最后:当您担心运行时时,简单的答案是:对输入数据进行切片,并使用2,4,8,...线程并行计算每个切片!但正如所说:在编写代码之前,我会做一些分析确保你真的需要花费宝贵的开发时间。不要解决假设的性能问题;专注于真正对您或您的用户至关重要的那些!
答案 1 :(得分:1)
使用x对数组中的每个项目进行Comap将花费O(n)时间。对数组进行排序将采用O(n log n),然后您可以使用二进制搜索,即O(log n),并获得总计O(n log n)。所以最有效的方法也是微不足道的 - 只需循环通过数组并将每个项目与x进行比较。
public static void main(String arg[] ){
int b[]={2, 4, 3, 4, 11, 13, 17};
int x=5;
int count=0;
for(int i=0;i<b.length;i++){
if(b[i]<x){
count++;
}
}
System.out.println(count);
}
答案 2 :(得分:0)
我建议您考虑以下方法,但仅当b
数组具有非负数时才有效。即使输入数组(a
和b
)未排序,该算法仍然有效。
<强>伪代码强>
max
的{{1}}元素。b
的新数组c
,并将max + 1
置于1
位置。创建一个大小为c[b[i]]
的新数组d
,并将其填充如下:
max + 1
d[0]=0;
创建一个大小为d[i]=d[i-1] + c[i];
的新数组e
,并将其填充如下:
n
if(a[i] > max) then e[i] = last(d)
otherwise e[i]=d[a[i]-1];
数组表示解决方案:它在第i个位置包含e
数组的数字的计数器,低于数组b
的第i个元素。
这个例子应该比伪代码更具说明性:
a
<强>复杂性强>
a = [5, 1, 4, 8, 17, 12, 22]
b = [2, 4, 3, 4, 11, 13, 17]
c = [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1]
d = [0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 6]
e = [3, 0, 2, 3, 5, 4, 6]
如果输入数组Steps 1, 2 and 4 are O(n).
Step 3 is O(max(b))
仅包含&#34; short&#34;算法在b
中执行的数字(max(b)与n
大小的顺序相同)。
可以优化该算法,创建大小为O(n)
的数组,并考虑max-min+1
数组低于0
的所有元素的计数器a
。
一个简单的java实现:
min(b)
答案 3 :(得分:0)
对于更大的排序集,我们需要使用分而治之原理来加快搜索速度。这是我的解决方案,具有O(logn)时间复杂度和O(n)空间复杂度。
public static void main(String arg[]) {
int x = 5;
int b[] = {2, 4, 3, 4, 11, 13, 17};
int high = b.length - 1;
int low = 0;
while (high >= low) {
int mid = (high + low) / 2;
if (b[mid] < x)
low = mid + 1;
else
high = mid - 1;
}
System.out.println(low);
}
答案 4 :(得分:-1)
这应该是一个可能的解决方案。所述&#34;昂贵&#34;任务是列表的排序。必须在for循环之前对bost列表进行排序。确保使用快速机制来执行排序。如上所述,对数组/数组列表进行排序是一种非常扩展操作,特别是如果有许多值需要排序。
public static void main(String[] args) throws IOException {
// int x = 5;
int a[] = { 1, 2, 3, 4, 5 };
int b[] = { 2, 4, 3, 4, 11, 13, 17 };
List<Integer> listA = new LinkedList<>();
for (int i : a) {
listA.add(i);
}
List<Integer> listB = new LinkedList<>();
for (int i : b) {
listB.add(i);
}
Collections.sort(listA);
Collections.sort(listB);
int smallerValues = 0;
int lastValue = 0;
Iterator<Integer> iterator = listB.iterator();
int nextValue = iterator.next();
for (Integer x : listA) {
while (nextValue < x && iterator.hasNext()) {
lastValue = nextValue;
nextValue = iterator.next();
if (nextValue > lastValue) {
smallerValues++;
}
}
System.out.println(x + " - " + smallerValues);
}
}