我有一个排序数组。给定一个键值(不一定在表中),我想找到表中关闭键值的元素。
我考虑使用二进制搜索,但如果键不在表中(不是-1),我需要返回最接近的元素。我该怎么做?
如果没有匹配项返回-1
。这是我目前使用二进制搜索的尝试:
public static long binarySearch (ArrayList<Long> arr, int first, int last, long key)
{
if (first > last) return -1;
int mid = first + (last - first)/2;
if (arr.get(mid) == key)
return mid;
else if (arr.get(mid) > key)
return binarySearch(arr, first, mid - 1, key);
else
return binarySearch(arr, mid + 1, last, key);
}
答案 0 :(得分:1)
更改:
if (first > last) return -1;
到
if (first > last) {
// if either first or last is negative, return the first element.
// if either first or last are greater than arr length, return the last element.
// otherwise, get values in the array for indecies first and last, compare then to
// your key and return the closest.
}
答案 1 :(得分:1)
尝试类似(未经测试)的内容:
public static Long getClosest(List<Long> sortedList, Long key) {
int index = Collections.binarySearch(sortedList, key);
Long closest;
if (index >= 0) {
closest = sortedList.get(index);
} else {
index = -index - 1;
if (index == 0){
closest = sortedList.get(index);
} else if (index == sortedList.size()){
closest = sortedList.get(index - 1);
} else {
Long prev = sortedList.get(index - 1);
Long next = sortedList.get(index);
closest = ((key - prev) < (next - key)) ? prev : next;
}
}
return closest;
}
如上所述,此代码未经测试,您可能需要检查它是否为所有极端情况返回正确的值。
答案 2 :(得分:0)
当中间位置的元素不等于键时,您可以将delta计算为abs(key-arr.get(mid))并检查它是否低于实际delta(最低delta,最接近的值''我有)。最后,如果在数组中找不到键,则返回delta而不是-1。
请注意,您不能将delta初始化为0,因为任何后来计算的delta都将大于0。
答案 3 :(得分:0)
这将解决问题,找到最接近的值,找到列表中接近索引的总和,例如{1,4,6,7,8,19}和密钥3.二进制搜索将最后的子集有1和4,
if(1 + 4> 3 + 3)?返回1否则返回4
if (first > last)
{
// This makes an Invalid case
return -1;
}
if (first == last)
{
// then get the valueOf(firstIndex)
return arr.get(first-1);
}
if (first + 1 == last)
{
// gets value from the first Index
int fistKey = arr.get(first-1);
// gets value from first Index + 1 i.e next Index
int nextKey = arr.get(first);
// if valueof(firstIndex) + valueOf(nextIndex) > key then,
// key will be closer to valueOf(firstIndex)
// else key will be closer to valueOf(nextIndex)
return ((fistKey + nextKey) > (key + key)) ? fistKey : nextKey;
}
else
{
// assuming List will start its index from 0, then "-1" used for mid calculation
int mid = (last+1)/2;
int keyFromList = arr.get(mid-1);
if (keyFromList == key)
return key;
if (keyFromList > key)
return binarySearch(arr, first, mid , key);
else
return binarySearch(arr, mid, last , key);
}
答案 4 :(得分:0)
幸运的是,Java标准库包含Arrays.binarySearch
,如果元素未包含在元素中,它会为您提供元素的“插入点”:
返回:搜索键的索引(如果它包含在数组中); 否则,( - (插入点) - 1)。插入点定义为 密钥插入数组的点: 第一个元素的索引大于键,或者a.length如果全部 数组中的元素小于指定的键。注意 这保证了当且仅当时,返回值将> = 0 钥匙被发现。
有了这个,我们可以非常简洁地实现您的要求:
import java.util.Arrays;
public class ClosestValue
{
static long closestValue(long[] sorted, long key)
{
if(sorted.length==1) {return sorted[0];} // trivial case
if(key<sorted[0]) {return sorted[0];} // lower boundary
if(key>sorted[sorted.length-1]) {return sorted[sorted.length-1];} // upper boundary
int pos = Arrays.binarySearch(sorted, key);
if(pos>=0) {return sorted[pos];} // we found an exact match
// we didn't find an exact match, now we have two candidates: insertion point and insertion point-1 (we excluded the trivial case before)
// pos = -ip-1 | +ip -pos => ip = -pos-1
int ip = -pos-1;
long closest;
if(sorted[ip]-key<key-sorted[ip-1]) {closest=sorted[ip];} // < can be <= if smaller value is preferred
else {closest=sorted[ip-1];}
return closest;
}
public static void main(String[] args)
{
System.out.println(closestValue(new long[] {1,4,6,7,8,19},3));
System.out.println(closestValue(new long[] {1,2,4,5},3));
System.out.println(closestValue(new long[] {1,2,4,5},7));
System.out.println(closestValue(new long[] {1,2,4,5},-5));
}
}