我有一个已经排序的数组列表。我希望将它放在一个排序的数据结构中,以便我可以轻松找到小于指定数量的项目数。
这就是我到目前为止的做法:
TreeSet<Integer> sortedList = new TreeSet<>(myArrayList); // This is slow
如果我想找到小于或等于50的数字(例如),那么我会这样做:
sortedList.headSet(50, true).size(); // This is not that slow
所有这些看起来都非常低效。这主要是因为myArrayList
已经排序并且初始化TreeSet非常慢。
请注意,数组列表非常大,查询数量非常少(大约10个)。
答案 0 :(得分:3)
如果您的myArrayList
已经排序且不包含重复项,则二进制搜索就是您的朋友。使用Collections.binarySearch
。 binarySearch
返回现有元素的索引(因此您有idx+1
个元素小于或等于)或插入点,其中应插入给定元素(所以{{1}是严格少于,没有相等元素的元素数量。
-idx-1
用法示例:
public static int countLessOrEqual(List<Integer> nums, int limit) {
int idx = Collections.binarySearch(nums, limit);
if(idx < 0) return -idx-1;
return idx+1;
}
如果您的输入列表已排序但包含重复项,则所有重复项都是相邻的,因此您可以预先处理列表并删除它们(比构建List<Integer> nums = Arrays.asList(1, 10, 23, 31, 50, 65, 71, 89, 100);
System.out.println(countLessOrEqual(nums, 50)); // 5
System.out.println(countLessOrEqual(nums, 51)); // 5
System.out.println(countLessOrEqual(nums, 49)); // 4
System.out.println(countLessOrEqual(nums, 0)); // 0
System.out.println(countLessOrEqual(nums, 300)); // 9
要快得多):
TreeSet
用法示例:
public static List<Integer> removeAdjacentDuplicates(List<Integer> input) {
List<Integer> result = new ArrayList<>();
Integer last = null;
for(int i=0; i<input.size(); i++) {
Integer cur = input.get(i);
if(i == 0 || !cur.equals(last))
result.add(cur);
last = cur;
}
return result;
}