我今天在接受采访时被问到这个问题。我尝试过一个解决方案,但想知道是否有更好的解决方法:
问题:我有一个arraylist说500,000个元素,使得arraylist的每个元素的值与索引相同。例如:list.get(0)= 0; list.get(1)= 1 ...等。但是只有一个元素与这个排序不同步[即list.get(i)!= i]。你怎么找到那个元素。
我的答案:使用多个线程迭代列表,每个线程在每次比较list.get(i)和i时处理arraylist的某个拼接。找到元素后,设置一些布尔变量以指示其他线程已找到该元素。
有没有办法解决这个问题而不迭代列表?还是更好的方式?
答案 0 :(得分:12)
在最糟糕的情况下,您必须检查每个元素,因此无法改善O(n)
时间复杂度。
考虑到这一点,最好的算法是从头到尾扫描阵列列表。这样就可以充分利用可用的内存带宽。
我并不完全清楚线程是如何或为何进入图片的。这似乎不合时宜。这是问题的一部分吗?
答案 1 :(得分:4)
答案是:一次迭代。你提到原因的并发性是他们正在捕捉的东西。
实际上从java 8开始,解决方案是否并行很简单。我认为最多会带来:
OptionalInt foundInt = IntStream.range(0, list.size())
.parallelStream()
.filter(i -> i != list.get(i))
.findAny();
答案 2 :(得分:2)
你不能比O(n)
做得更好。
其次,我认为在这些问题中谈论线程和多线程是一个坏主意。它们根本不感兴趣。最后,你有一个O(无论如何)的运行时,你的常量被移除了。
也许面试官意味着一个排序数组,其元素从0到n-1,索引0到n-1。然后将一个元素移动到不同的位置。但这意味着所有剩余的元素都有不同的索引!在这种情况下,您可以使用二分查找改进搜索:
然后你可以在O(log n)
中获取元素。从中间开始,检查索引是否等于元素。如果相等,则对半部的上半部分进行相同的处理,如果不使用另一部分的话。
答案 3 :(得分:0)
继续@ aix的回答,如何对每个循环进行2次检查:
for (int i = 0; i < list.size / 2; i++)
{
if (i != list.get(i))
{
return i;
}
else if (list.size - i != list.get(list.size - i)
{
return list.size - i;
}
}
答案 4 :(得分:0)
1. iterate through the list
2. check for the condition in the elements
3. when that only element found break out the loop...
我不认为Thread进入竞技场......
答案 5 :(得分:0)
ArrayList<Integer> s = new ArrayList<Integer>();
for (int i=0; i<500000; i++) {
s.add(i);
}
s.set(13, 500002);
for (int j=0; j<s.size(); j++) {
if (j != s.get(j)) {
System.out.println(j + " " + s.get(j));
}
}