【问题标题】:find closest element in ArrayList在 ArrayList 中找到最近的元素
【发布时间】:2014-12-16 23:39:25
【问题描述】:

我有一个排序数组。给定一个键值(不一定在表中),我想在表中找到接近键值的元素。

我考虑过使用二进制搜索,但如果键不在表中(不是-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);
}   

【问题讨论】:

  • 你有什么问题?
  • “最接近”是什么意思?
  • 例如{1,4,6,7,8,19},如果key为3,则方法必须返回4
  • {1,2,4,5},key是3,哪个最接近?
  • 听起来像你想要的NavigableSet

标签: java binary-search


【解决方案1】:

变化:

if (first &gt; 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.

}

【讨论】:

    【解决方案2】:

    尝试类似(未经测试):

    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;
    } 
    

    如前所述,此代码未经测试,您可能需要检查它是否为所有极端情况返回正确的值。

    【讨论】:

      【解决方案3】:

      当中间位置的元素不等于key时,可以将delta计算为abs(key-arr.get(mid))并检查它是否低于实际delta(最低的delta,最接近的值你'有)。最后,如果你没有在数组中找到键,你返回 delta 而不是 -1。

      请注意,您不能将 delta 初始化为 0,因为以后计算的任何 delta 都将大于 0。

      【讨论】:

        【解决方案4】:

        这将解决问题,找到最接近的值,找到 List 中接近索引的总和,例如 {1,4,6,7,8,19} 和键 3。二分查找将具有 1 和 4 的最终子集,

        如果 (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);
            } 
        

        【讨论】:

          【解决方案5】:

          幸运的是,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));
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-09-09
            • 2013-05-07
            • 2022-06-27
            • 1970-01-01
            • 2023-03-20
            • 2019-07-07
            • 2016-12-28
            相关资源
            最近更新 更多