Найдите самое близкое число в списке чисел

У меня есть список постоянных чисел. Я должен найти самое близкое число к x в списке чисел. Какие-либо идеи о том, как реализовать этот алгоритм?

7
задан DanM7 5 October 2012 в 23:40
поделиться

7 ответов

Ну, вы не можете сделать это быстрее, чем O(N), потому что вы должны проверить все числа, чтобы убедиться, что у вас есть ближайший. Тем не менее, почему бы не использовать простую вариацию по нахождению минимума, и не искать тот, который имеет минимальную абсолютную разницу с x?

Если вы можете сказать, что список упорядочен с самого начала (и он позволяет случайный доступ, как массив), то лучшим подходом будет использование бинарного поиска. Когда вы завершаете поиск по индексу i (не найдя x), просто выберете лучший из этого элемента и его соседей.

.
8
ответ дан 6 December 2019 в 11:49
поделиться

Я полагаю, что массив неупорядочен. В упорядоченном виде он может быть быстрее

Я думаю, что самым простым и быстрым методом является использование линейного алгоритма нахождения минимума или максимума, но вместо сравнения значений вы будете сравнивать абсолютное значение разницы между этим и иглой.

На языке Си++ ( я не могу на Си#, но он будет похож ) код может выглядеть так:

// array of numbers is haystack
// length is length of array
// needle is number which you are looking for ( or compare with )

int closest = haystack[0];
for ( int i = 0; i < length; ++i ) {
  if ( abs( haystack[ i ] - needle ) < abs( closest - needle ) ) closest = haystack[i];
}
return closest;
5
ответ дан 6 December 2019 в 11:49
поделиться

В общем люди на этом сайте не будут делать за вас домашнее задание. Так как вы не написали код, я тоже не буду писать код. Однако, вот один из возможных подходов.

Просмотрите список, вычитая число в списке из x. Возьмите абсолютное значение этой разницы и сравните его с лучшим полученным вами предыдущим результатом, а если текущая разница меньше лучшего предыдущего результата, сохраните текущее число из списка. В конце цикла вы получите ответ

.
3
ответ дан 6 December 2019 в 11:49
поделиться

Это можно сделать с помощью SortedList:
Пост в блоге о нахождении ближайшего номера
Если искомая сложность имеет значение только для поиска, то сложность равна O(log(n)). Построение списка будет стоить O(n*log(n))

Если вы собираетесь вставить элемент в список намного больше раз, чем запросить для ближайшего номера, то лучший выбор - это использовать List и использовать наивный алгоритм для запроса ближайшего номера. Каждый поиск будет стоить O(n), но время для вставки сократится до O(n).

Общая сложность: Если коллекция имеет n номеров и искала q раз -
List: O(n+q*n)
Sorted List: O(n*log(n)+q*log(n))

Значит, из некоторого q отсортированный список обеспечит большую сложность.

.
0
ответ дан 6 December 2019 в 11:49
поделиться

Хаскелл:

import Data.List (minimumBy)
import Data.Ord (comparing)

findClosest :: (Num a, Ord a) => a -> [a] -> Maybe a
findClosest _ [] = Nothing
findClosest n xs = Just $ minimumBy (comparing $ abs . (+ n)) xs
0
ответ дан 6 December 2019 в 11:49
поделиться
private int? FindClosest(IEnumerable<int> numbers, int x)
{
    return
        (from number in numbers
        let difference = Math.Abs(number - x)
        orderby difference, Math.Abs(number), number descending
        select (int?) number)
        .FirstOrDefault();
}

Нуль означает, что ближайшего числа не было. Если есть два числа с одинаковой разницей, то он выберет ближайшее к нулю. Если два числа находятся на одинаковом расстоянии от нуля, то будет выбрано положительное число.

Редактирование в ответ на комментарий Эрика:

Вот вариант, который имеет одинаковую семантику, но использует оператор Min. Он требует реализации IComparable<>, чтобы можно было использовать Min, сохраняя при этом число, которое идет с каждого расстояния. Я также сделал его методом расширения для простоты использования:

public static int? FindClosestTo(this IEnumerable<int> numbers, int targetNumber)
{
    var minimumDistance = numbers
        .Select(number => new NumberDistance(targetNumber, number))
        .Min();

    return minimumDistance == null ? (int?) null : minimumDistance.Number;
}

private class NumberDistance : IComparable<NumberDistance>
{
    internal NumberDistance(int targetNumber, int number)
    {
        this.Number = number;
        this.Distance = Math.Abs(targetNumber - number);
    }

    internal int Number { get; private set; }

    internal int Distance { get; private set; }

    public int CompareTo(NumberDistance other)
    {
        var comparison = this.Distance.CompareTo(other.Distance);

        if(comparison == 0)
        {
            // When they have the same distance, pick the number closest to zero
            comparison = Math.Abs(this.Number).CompareTo(Math.Abs(other.Number));

            if(comparison == 0)
            {
                // When they are the same distance from zero, pick the positive number
                comparison = this.Number.CompareTo(other.Number);
            }
        }

        return comparison;
    }
}
1
ответ дан 6 December 2019 в 11:49
поделиться

Быть ленивым, я не проверяет это, но не должен эту работу

private int FindClosest(IEnumerable<int> numbers, int x)
{
    return
        numbers.Aggregate((r,n) => Math.Abs(r-x) > Math.Abs(n-x) ? n
                                 : Math.Abs(r-x) < Math.Abs(n-x) ? r
                                 : r < x ? n : r);
}
0
ответ дан 6 December 2019 в 11:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: