给定数字current
,找到数组中大于和小于该值的值的数量。
//sort array for binary search
int[] digits = Arrays.stream(sc.nextLine()
.split(" "))
.mapToInt(Integer::parseInt)
.sorted()
.toArray();
//for duplicate values, find higher index of current.
while(low <= high){
int mid = low + (high - low)/2;
if(digits[mid] > current){
high = mid - 1;
}else if (digits[mid] == current){
startindex = mid;
high = mid - 1;
}else{
startindex = mid;
low = mid +1;
}
}
//for duplicate values, find lower index of current.
int endindex = -1;
low = 0;
high = no_digits - 1;
while(low <= high){
int mid = low + (high - low)/2;
if(digits[mid] > current){
high = mid - 1;
}else if (digits[mid] == current){
endindex = mid;
low = mid + 1;
}else{
endindex = mid;
low = mid + 1;
}
}
System.out.println(endindex + "-" + startindex);
if(digits[0] > current){
smallest = 0;
largest = no_digits;
System.out.println(String.format("Smaller: %d, Greater: %d", smallest, largest));
} else if (digits[no_digits - 1] < current){
smallest = no_digits;
largest = 0;
System.out.println(String.format("Smaller: %d, Greater: %d", smallest, largest));
}else {
smallest = startindex;
largest = no_digits - endindex - 1;
System.out.println(String.format("Smaller: %d, Greater: %d", smallest, largest));
}
}
}
示例输入:
5 8 7 2 4 3 7 9 1 9 - Array of ints.
7
0
100
3
6
输出:
Smaller: 5, Greater: 3
Smaller: 0, Greater: 10
Smaller: 10, Greater: 0
Smaller: 2, Greater: 7
Smaller: 5, Greater: 5
我的结果:
6-5 //start and end index.
Smaller: 5, Greater: 3
-1--1
Smaller: 0, Greater: 10
9-9
Smaller: 10, Greater: 0
2-2
Smaller: 2, Greater: 7
4-4
Smaller: 5, Greater: 4
我设法推出了上述算法,该算法考虑的值大于或低于数组中的任何值。
但是,由于我需要在O((N + Q)log N)时间内完成上述操作,因此我无法找到解决数组中不存在的值而无需迭代数组的解决方案。
在这种情况下,这将是值为6
的最后一个测试用例。数组中不存在6,但我仍然需要计算高于/低于6的所有值。
答案 0 :(得分:3)
二进制搜索算法为数组中不存在的值生成“插入点”。您的startIndex
和endIndex
会为您提供第一个“符合条件”的项目,或者旁边的项目。换句话说,如果您要查找小于6
的所有值,搜索端点将产生5
的索引。
请注意,您不需要滚动自己的二进制搜索算法:Java为您提供了一个实现。
答案 1 :(得分:2)
编辑这个问题已被编辑,现在它还包含一个额外的要求,即算法应该能够快速地进行多个查询,更准确地说:整个运行时应该是O((N + Q) * log(N))
其中{{1是数组的大小,N
是查询的数量。
以下方法仅适用于Q
。
我没有看到任何理由不在线性Q = 1
时间内这样做。
O(N)
输出:
// get this from scanner
int number = 5;
int[] array = {6, 2, 7, 4, 1, 42};
// the "algorithm"
int numLessThan = 0;
int numGreaterThan = 0;
for (int i: array) {
if (i < number) numLessThan++;
if (i > number) numGreaterThan++;
}
System.out.println(
"Num greater than: " + numGreaterThan + " " +
"Num less than: " + numLessThan
);
如果你坚持用溪流做这件事:
Num greater than: 3 Num less than: 3
即使它遍历数组两次,它仍然是long numLessThan = Arrays.stream(array).filter(x -> x < number).count();
long numGreaterThan = Arrays.stream(array).filter(x -> x > number).count();
。
答案 2 :(得分:2)
由于您使用Client
,Stream
- 呼叫不少,您仍然会重复整个阵列。
所以就这样做
map
或更通用的版本
class Counters {
AtomicInteger smaller = new AtomicInteger(0);
AtomicInteger larger = new AtomicInteger(0);
private final int upperLimit;
private final int lowerLimit;
public Counters(int up, int down) {
upperLimit = up;
lowerLimit = down;
}
public void consider(int value) {
if (value > upperLimit) larger.incrementAndGet();
if (value < lowerLimit) smaller.incrementAndGet();
}
public int getSmaller() { return smaller.get(); }
public int getLarger() { return larger.get(); }
}
Counters c = new Counters(upper, lower);
IntStream.of(yourValues).parallel().forEach(c::consider);
// your output here
System.out.printf("Smaller: %d - Larger: %d", c.getSmaller(), c.getLarger());
答案 3 :(得分:1)
请参阅Arrays,这将会派上用场。
void stats(int[] a, int sought) {
a = Arrays.copyOf(a, a.length);
Arrays.sort(a);
int index = Arrays.binarySearch(a, sought);
int smaller, larger;
if (index < 0) {
// Not found.
index = ~index; // Insertion position.
smaller = index;
larger = index:
} else {
// Found.
smaller = index;
while (smaller > 0 && a[smaller] == sought) {
--smaller;
}
while (index <= 0 && a[index] == sought) {
++index;
}
}
larger = a.length - index;
int equals = index - smaller;
System.out.printf("Smaller %d, equal %d, larger %d.%n",
smaller, equals, larger);
}
如您所见,找到一个元素时,回路O(N)就足够了,它小于排序O(N log N)。
更快 - O(log N)代替那个部分的O(N) - 如果有人可以对搜索的二进制搜索 - 0.5并且寻求+ 0.5。
void stats(int[] a, int sought) {
a = Arrays.copyOf(a, a.length);
for (int i = 0; i < a.length; ++i) {
a[i] *= 2;
}
Arrays.sort(a);
int smallerI = Arrays.binarySearch(a, 2 * sought - 1);
int largerI = Arrays.binarySearch(a, 2 * sought + 1);
int smaller = ~smallerI;
int larger = a.length - ~largerI;
int equals = ~largerI - ~smallerI;
System.out.printf("Smaller %d, equal %d, larger %d.%n",
smaller, equals, larger);
}
这使用了加倍的整数,其缺点是数组值的有效域减半。
在你的情况下,你自己的二元搜索算法应该选择后一种情况(不加倍),使用隐式sought + 0.5
,永远不会找到,寻找插入位置。
答案 4 :(得分:1)
好的,所以在你编辑之后你说你要在同一个数组上运行几个查询,所以准备时间不那么重要。
为此,从数组中构建red-black tree;这将为您提供一个允许在O(log N)中搜索的排序结构。
那么你为&#34;较小的&#34;做了什么? count是向左移动,直到找到一个值等于或大于下限的节点;算上所有左边的孩子。模拟较大的(向右,找到相等或更小,向右计数)。
如果项目不在数组中,那将无关紧要,因为您正在寻找一个“等于或大于”的数据。如果是6不存在,但是你找到了5,你从那里开始计算 - 只有你在计数中加1。
答案 5 :(得分:0)
您只需要过滤然后计算出现次数。例如:
public static void main(String[] args) {
int[] values = {5, 8, 7, 2, 4, 3, 7, 9, 1, 9};
printCount(values, 7);
printCount(values, 0);
printCount(values, 100);
printCount(values, 3);
printCount(values, 6);
}
private static void printCount(int[] values, int value) {
long smallerCount = Arrays.stream(values).filter(v -> v < value).count();
long largerCount = Arrays.stream(values).filter(v -> v > value).count();
System.out.println(String.format("Smaller : %d, Larger: %d", smallerCount, largerCount));
}