我有一组静态的有序数字{1,2,4,10,14,20,21,24,29,30},可以存储在任何集合中。如果传入新号码,我需要能够找到最接近新号码的号码。
例如: 如果我的静态有序数集是{1,2,4,10,14,20,21,24,29,30}。 传入的数字是23,最接近的数字是24。
我考虑过将静态数字存储到数组中。循环数组,然后尝试找到最接近的数字,但此解决方案是O(n)。有更快的方法吗?
答案 0 :(得分:3)
假设整数数组已排序,那么您可以使用Arrays.binarySearch(array, key)
。
binarySearch
调用的结果是数组中键的偏移量或“插入点”;即需要插入密钥的偏移量。如果获得插入点(表示为负数),则可以使用它来标识数组中的下一个最大或下一个最小数字。 (“插入点”的确切含义和表示在javadoc中进行了解释。)
此程序的复杂性为O(logN)
。
这比使用Collections.binarySearch
更快,因为后者需要将int[]
转换为Integer[]
,然后才能将其包装在列表中。如果你开始使用Integer[]
,那么Arrays.binarySearch
的替代重载将适用于任何对象数组。
它也比从输入数组创建TreeSet
更快。但是,TreeSet的优势在于,一旦创建了集合,与基于数组或基于arraylist的表示相比,更新将更便宜。 (但更新不是上述要求的一部分。)
答案 1 :(得分:1)
在Java 1.6中,有NavigableSet接口。 TreeSet和ConcurrentSkipListSet都实现了这个接口。它是SortedSet的子接口,用于替换SortedSet。
所以,你现在已经在这个NavigableSet中获得了你的收藏。您现在有两个方法 - floor和ceiling分别返回小于或大于参数的元素,如果有一个则返回相等,如果没有这样的元素则返回null。
有了这个,你可以做一些事情:
int closest(int arg) {
Integer ceil = set.ceiling(arg);
Integer floor = set.floor(arg);
if(ceil == null) { return floor; }
if(floor == null) { return ceil; }
int cdiff = ceil - arg;
int fdiff = arg - floor;
if(cdiff < fdiff) { return ceil; }
else { return floor; }
}
意识到对于小型阵列,此实现与其他实现之间的速度差异可能可以忽略不计。
如果您正在处理大量数字,您可能希望实现自己的skip list(它是一个整齐的数据结构),其底层是双重链接。然后你可以到达值应该的地方,如果不是,可以轻松上下水平以获得下一个更高和更低的数字。
答案 2 :(得分:0)
如果您有有序列表,可以将其放在列表中并拨打Collections.binarySearch(list, valueToCheck)
如果返回索引为负,那么您需要将其转换为相应的正索引并确保该数字大于传入的数字(应将其转换为正数,只需注意它是否为正数)大于列表中的最后一个数字。)