我接受了采访,并有以下问题:
在小于O(n)的时间内从排序数组中查找唯一数字。
Ex: 1 1 1 5 5 5 9 10 10 Output: 1 5 9 10
我给出了解决方案,但那是O(n)。
编辑:排序数组大小约为200亿,唯一数字约为1000。
答案 0 :(得分:14)
我认为不能在低于O(n)的情况下完成。在数组包含1 2 3 4 5
的情况下:为了获得正确的输出,必须查看数组的每个元素,因此O(n)。
答案 1 :(得分:14)
分而治之:
data[0]..data[data.length-1]
)。 在平均情况下以 O(log(n))求解,而在最坏的情况下(当每个元素不同时)求解O(n)。
Java代码:
public static List<Integer> findUniqueNumbers(int[] data) {
List<Integer> result = new LinkedList<Integer>();
findUniqueNumbers(data, 0, data.length - 1, result, false);
return result;
}
private static void findUniqueNumbers(int[] data, int i1, int i2, List<Integer> result, boolean skipFirst) {
int a = data[i1];
int b = data[i2];
// homogenous sequence a...a
if (a == b) {
if (!skipFirst) {
result.add(a);
}
}
else {
//divide & conquer
int i3 = (i1 + i2) / 2;
findUniqueNumbers(data, i1, i3, result, skipFirst);
findUniqueNumbers(data, i3 + 1, i2, result, data[i3] == data[i3 + 1]);
}
}
答案 2 :(得分:4)
如果您的排序数组n
包含m
个不同的元素,则可以执行O(mlogn)
。
请注意,m << n (eg m=2 and n=100)
算法:
初始化:当前元素y = first element x[0]
步骤1:对y
中x
的最后一次出现进行二元搜索(可以在O(log(n))
时间内完成。让它的索引为{{1} }
第2步:i
并转到第1步
编辑:如果y = x[i+1]
此算法运行不正常。为了缓解它,您可以使用常规m = O(n)
算法并行运行它。元算法由我的算法和并行运行的O(n)
算法组成。当这两种算法中的任何一种完成时,元算法就会停止。
答案 3 :(得分:0)
由于数据由整数组成,因此在任意两个值之间可能存在有限数量的唯一值。因此,首先查看数组中的第一个和最后一个值。如果a[length-1] - a[0] < length - 1
,则会有一些重复值。将a[0]
和a[length-1]
放入一个像散列集一样的常量访问时容器中。如果这两个值相等,那么您可以知道数组中只有一个唯一值,您就完成了。您知道数组已排序。因此,如果两个值不同,您现在可以查看中间元素。如果中间元素已经在值集中,则您知道可以跳过数组的整个左侧部分,并且只能递归地分析右侧部分。否则,递归地分析左右两部分。
根据数组中的数据,您将能够在不同数量的操作中获取所有唯一值的集合。如果所有值都相同,那么你可以在恒定时间O(1)
得到它们,因为只有在检查了第一个和最后一个元素之后你就会知道它。如果有相对较少的&#34;唯一值,您的复杂性将接近O(log N)
,因为在每个分区之后,您将经常&#34;经常&#34;能够丢弃至少一半分析的子阵列。如果值都是唯一且a[length-1] - a[0] = length - 1
,您还可以定义&#34;设置为恒定时间,因为它们必须是从a[0]
到a[length-1]
的连续数字。但是,为了实际列出它们,您必须输出每个数字,并且有N个。
也许有人可以提供更正式的分析,但我的估计是这个算法在唯一值的数量上大致是线性的而不是数组的大小。这意味着如果只有很少的唯一值,即使对于一个庞大的数组,也可以在很少的操作中得到它们(例如,如果只有一个唯一值,则无论数组大小如何都在恒定时间内)。由于唯一值的数量不比数组的大小大,我声称这使得该算法比O(N)&#34;更好。 (或严格地说:&#34;不比O(N)差,在许多情况下更好&#34;)。
答案 4 :(得分:0)
import java.util.*;
/**
* remove duplicate in a sorted array in average O(log(n)), worst O(n)
* @author XXX
*/
public class UniqueValue {
public static void main(String[] args) {
int[] test = {-1, -1, -1, -1, 0, 0, 0, 0,2,3,4,5,5,6,7,8};
UniqueValue u = new UniqueValue();
System.out.println(u.getUniqueValues(test, 0, test.length - 1));
}
// i must be start index, j must be end index
public List<Integer> getUniqueValues(int[] array, int i, int j) {
if (array == null || array.length == 0) {
return new ArrayList<Integer>();
}
List<Integer> result = new ArrayList<>();
if (array[i] == array[j]) {
result.add(array[i]);
} else {
int mid = (i + j) / 2;
result.addAll(getUniqueValues(array, i, mid));
// avoid duplicate divide
while (mid < j && array[mid] == array[++mid]);
if (array[(i + j) / 2] != array[mid]) {
result.addAll(getUniqueValues(array, mid, j));
}
}
return result;
}
}