Find the nearest / closest value in a sorted list

I was wondering if it is possible to find the nearest element in Listfor an element that is not .

For example, if we had values ​​[1,3,6,7] and we are looking for the element closest to 4, it should return 3, because 3 is the largest number in the array that is less than 4.

I hope this makes sense because English is not my first language.

+4
source share
5 answers

If the array is sorted, you can perform a modified binary search in O( log n ):

    public static int search(int value, int[] a) {

        if(value < a[0]) {
            return a[0];
        }
        if(value > a[a.length-1]) {
            return a[a.length-1];
        }

        int lo = 0;
        int hi = a.length - 1;

        while (lo <= hi) {
            int mid = (hi + lo) / 2;

            if (value < a[mid]) {
                hi = mid - 1;
            } else if (value > a[mid]) {
                lo = mid + 1;
            } else {
                return a[mid];
            }
        }
        // lo == hi + 1
        return (a[lo] - value) < (value - a[hi]) ? a[lo] : a[hi];
    }
+13
source

You need Array.binarySearch, the docs .

: , ; (- ( ) - 1). , : , , , a.length, .

+6

NavigableSet, higher lower.

+5

, - , .

List<Integer> ints = new ArrayList<>();
ints.add(1);
ints.add(3);
ints.add(6);
ints.add(7);

Collections.sort(ints);

int target = 4;
int nearest = 0;

for (int i : ints)
{
    if (i <= target) {
        nearest = i;
    }
}

System.out.println(nearest);

, target.

+1

, , , . 3 :

  • -,
  • ,

Python:

def closest_value(arr, target):
  def helper(arr, target, lo, hi, closest_so_far):
    # Edge case
    if lo == hi:
      mid = lo
      if abs(arr[mid] - target) < abs(arr[closest_so_far] - target):
        closest_so_far = mid
      return closest_so_far

    # General case
    mid = ((hi - lo) >> 1) + lo

    if arr[mid] == target:
      return mid

    if abs(arr[mid] - target) < abs(arr[closest_so_far] - target):
      closest_so_far = mid

    if arr[mid] < target:
      # Search right
      return helper(arr, target, min(mid + 1, hi), hi, closest_so_far)
    else:
      # Search left
      return helper(arr, target, lo, max(mid - 1, lo), closest_so_far)


  if len(arr) == 0:
    return -1
  return helper(arr, target, 0, len(arr) - 1, arr[0])


arr = [0, 10, 14, 27, 28, 30, 47]

attempt = closest_value(arr, 26)
print(attempt, arr[attempt])
assert attempt == 3

attempt = closest_value(arr, 29)
print(attempt, arr[attempt])
assert attempt in (4, 5)


def closest_values(arr, target):
  def left_helper(arr, target, abs_diff, lo, hi):
    # Base case
    if lo == hi:
      diff = arr[lo] - target
      if abs(diff) == abs_diff:
        return lo
      else:
        return lo + 1

    # General case
    mid = ((hi - lo) >> 1) + lo
    diff = arr[mid] - target
    if diff < 0 and abs(diff) > abs_diff:
      # Search right
      return left_helper(arr, target, abs_diff, min(mid + 1, hi), hi)
    elif abs(diff) == abs_diff:
      # Search left
      return left_helper(arr, target, abs_diff, lo, max(mid - 1, lo))
    else:
      # Search left
      return left_helper(arr, target, abs_diff, lo, max(mid - 1, lo))


  def right_helper(arr, target, abs_diff, lo, hi):
    # Base case
    if lo == hi:
      diff = arr[lo] - target
      if abs(diff) == abs_diff:
        return lo
      else:
        return lo - 1

    # General case
    mid = ((hi - lo) >> 1) + lo
    diff = arr[mid] - target
    if diff < 0 and abs(diff) > abs_diff:
      # Search right
      return right_helper(arr, target, abs_diff, min(mid + 1, hi), hi)
    elif abs(diff) == abs_diff:
      # Search right
      return right_helper(arr, target, abs_diff, min(mid + 1, hi), hi)
    else:
      # Search left
      return right_helper(arr, target, abs_diff, lo, max(mid - 1, lo))


  a_closest_value = closest_value(arr, target)
  if a_closest_value == -1:
    return -1, -1

  n = len(arr)
  abs_diff = abs(arr[a_closest_value] - target)
  left = left_helper(arr, target, abs_diff, 0, a_closest_value)
  right = right_helper(arr, target, abs_diff, a_closest_value, n - 1)
  return left, right


arr = [0, 10, 14, 27, 27, 29, 30]

attempt = closest_values(arr, 28)
print(attempt, arr[attempt[0] : attempt[1] + 1])
assert attempt == (3, 5)

attempt = closest_values(arr, 27)
print(attempt, arr[attempt[0] : attempt[1] + 1])
assert attempt == (3, 4)
-1

All Articles