【发布时间】:2018-03-02 05:30:00
【问题描述】:
Java Array 有一个binarySearch 方法,它返回数组中给定键的索引。但是,如果存在重复,则此 binarySearch 不保证会找到哪个元素
例子:
- 给出了一个数字数组
[5 8 7 2 4 3 7 9 1 9]。 - 对该数组排序
[1 2 3 4 5 7 7 8 9 9]。 - 使用给定的键对其执行二进制搜索。
- 对于返回的每个索引,打印低于和高于它的元素数。
对于键 7,给定索引 5 - 较小元素的数量将为“5”,更大的元素数量为“3”,因为有 2 个7。
对于键“0”,将给出索引“-1”,因为没有比它小的元素。 Smaller: 0, Greater: 10.
对于键“100”,将给出索引“-11”,因为没有大于它的元素。 Smaller: 10, Greater: 0.
对于键“6”,将给出索引“-6”。数组中不存在元素。 Smaller: 5, Greater: 5.
算法:
public class Counting {
private void run() {
Scanner sc = new Scanner(System.in);
int no_digits = Integer.parseInt(sc.nextLine());
int[] digits = new int[no_digits];
for (int i = 0; i < no_digits; i++) {
digits[i] = sc.nextInt();
}
sc.nextLine();
Arrays.sort(digits);
int no_queries = Integer.parseInt(sc.nextLine());
for (int i = 0; i < no_queries; i++) {
int key = sc.nextInt();
int upper = 0;
int lower = Arrays.binarySearch(digits, key);
if(lower == -1){
lower = 0;
upper = no_digits;
}else if(Math.abs(lower) > no_digits){
lower = no_digits;
upper = 0;
}else if(lower <= 0){
lower = Math.abs(lower) - 1;
upper = no_digits - lower;
} else {
int value = digits[lower];
int j = 0;
int k = 0;
high: while(digits[lower + j] == value){
j++;
if((lower + j) > no_digits - 1){
break high;
}
}
upper = no_digits - lower - j;
low: while(digits[lower - k] == value){
k++;
if((lower - k) < 0){
break low;
}
}
lower = lower - k + 1;
}
System.out.println("Smaller: " + lower + ", Greater: " + upper);
}
sc.close();
}
public static void main(String[] args) {
Counting newCounting = new Counting();
newCounting.run();
}
}
这可行,但是其中一个测试用例的算法从头到尾遍历数组多次,这导致算法需要相当长的时间才能完成。
示例:包含 100 位数字的数组,其中前半部分为 1,后半部分为 100。
如果我搜索1,索引可能会返回34,因为无法保证会找到哪个索引。然后我的算法将从索引34 开始遍历数组,只得到Smaller: 0, Greater: 50,因为数组的上半部分都是数字100。
有没有办法提高效率?我的目标是O((N+Q) log N) 复杂性,其中Q 是查询数,K 是数组中的整数数。
【问题讨论】:
-
您是否只限于使用二分搜索或其他算法?
-
其他算法也可以。
-
我没有看到你的主要目标。你知道
lower_bound和upper_bound类型的二分搜索(名称来自 C++STL,但方法和实现在其他地方可用)?