Двоичный поиск для нахождения вращения указывает в повернутом отсортированном списке

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

Позволяет предполагают, что первоначальный список {1,2,3,4,5,6,7,8}, повернутый список может быть похожим {5,6,7,8,1,2,3,4}

Нормальный двоичный поиск не работает в этом случае. Любая идея, как сделать это.

- Редактирование

У меня есть друг друг условие. Что, если список не отсортирован??

17
задан Gabriel Rodriguez 7 February 2013 в 11:33
поделиться

7 ответов

Все, что вам нужно, - это небольшая модификация алгоритма двоичного поиска; вот решение в полностью работоспособной Java (см. ответ Серга для реализации Delphi и ответ tkr для визуального объяснения алгоритма).

import java.util.*;
public class BinarySearch {
    static int findMinimum(Integer[] arr) {
        int low = 0;
        int high = arr.length - 1;
        while (arr[low] > arr[high]) {
            int mid = (low + high) >>> 1;
            if (arr[mid] > arr[high]) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }
    public static void main(String[] args) {
        Integer[] arr = { 1, 2, 3, 4, 5, 6, 7 };
        // must be in sorted order, allowing rotation, and contain no duplicates

        for (int i = 0; i < arr.length; i++) {
            System.out.print(Arrays.toString(arr));
            int minIndex = findMinimum(arr);
            System.out.println(" Min is " + arr[minIndex] + " at " + minIndex);
            Collections.rotate(Arrays.asList(arr), 1);
        }
    }
}

Это печатает:

[1, 2, 3, 4, 5, 6, 7] Min is 1 at 0
[7, 1, 2, 3, 4, 5, 6] Min is 1 at 1
[6, 7, 1, 2, 3, 4, 5] Min is 1 at 2
[5, 6, 7, 1, 2, 3, 4] Min is 1 at 3
[4, 5, 6, 7, 1, 2, 3] Min is 1 at 4
[3, 4, 5, 6, 7, 1, 2] Min is 1 at 5
[2, 3, 4, 5, 6, 7, 1] Min is 1 at 6

См. Также


На дубликатах

Обратите внимание, что дублирование делает невозможным для этого в O (log N) .Рассмотрим следующий битовый массив, состоящий из множества 1 и одного 0 :

  (sorted)
  01111111111111111111111111111111111111111111111111111111111111111
  ^

  (rotated)
  11111111111111111111111111111111111111111111101111111111111111111
                                               ^

  (rotated)
  11111111111111101111111111111111111111111111111111111111111111111
                 ^

Этот массив можно повернуть N способами и найти 0 в O (log N) невозможно, поскольку нет способа определить, находится ли он слева или справа от «середины».


У меня одно другое состояние. Что делать, если список не отсортирован ??

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

См. Также

26
ответ дан 30 November 2019 в 10:39
поделиться

Вот изображение, иллюстрирующее предлагаемые алгоритмы:

alt text

9
ответ дан 30 November 2019 в 10:39
поделиться

Версия Delphi - третья улучшенная (благодаря коду polygenelubricants - еще одно сравнение удалено) вариант:

type
  TIntegerArray = array of Integer;

function MinSearch(A: TIntegerArray): Integer;
var
  I, L, H: Integer;

begin
  L:= Low(A);   // = 0
  H:= High(A);  // = Length(A) - 1
  while A[L] > A[H] do begin
    I:= (L + H) div 2; // or (L + H) shr 1 to optimize
    Assert(I < H);
    if (A[I] > A[H])
      then L:= I + 1
      else H:= I;
  end;
  Result:= A[L];
end;
2
ответ дан 30 November 2019 в 10:39
поделиться

Что-то вроде этого может сработать (не проверено):

//assumes the list is a std::vector<int> myList

int FindMinFromRotated(std::vector<int>::iterator begin, std::vector<int>::iterator end) {
    if (begin == end)
        throw std::invalid_argument("Iterator range is singular!");
    if (std::distance(begin, end) == 1) //What's the min of one element?
        return *begin;
    if (*begin < *end) //List is sorted if this is true.
        return *begin;
    std::vector<int>::iterator middle(begin);
    std::advance(middle, std::distance(begin, end)/2);
    if (*middle < *begin) //If this is true, than the middle element selected is past the rotation point
        return FindMinFromRotated(begin, middle)
    else if (*middle > *begin) //If this is true, the the middle element selected is in front of the rotation point.
        return FindMinFromRotated(middle, end)
    else //Looks like we found what we need :)
        return *begin;
}
1
ответ дан 30 November 2019 в 10:39
поделиться

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

http://en.wikipedia.org/wiki/Ternary_search

edit При повторном прочтении я, вероятно, неправильно понял вопрос: функция не соответствует требованиям троичного поиска :/ Но разве двоичный поиск не работает? Предположим, исходный порядок был возрастающим.

if (f(left) < f(middle)) 
    // which means, 'left' and 'middle' are on the same segment (before or after point X we search)
    // and also 'left' is before X by definition
    // so, X must be to the right from 'middle'
    left = middle
else
    right = middle
3
ответ дан 30 November 2019 в 10:39
поделиться

Просто выполните метод деления пополам в списке - list [end] в диапазоне [1, end). Метод деления пополам ищет нули в функции путем поиска изменения знака и работает в O (log n).

Например,

{5,6,7,8,1,2,3,4} -> {1,2,3,4, -3, -2, -1,0}

Затем используйте (дискретизированный) метод деления пополам в этом списке {1,2,3,4, -3, -2, -1}. Он найдет нулевое пересечение между 4 и -3, что соответствует вашей точке вращения.

3
ответ дан 30 November 2019 в 10:39
поделиться

Выберите некоторую подпоследовательность [i, j] из списка [первый, последний) . Либо [i, j] не содержит разрыва, и в этом случае * i <= * j , либо содержит, и в этом случае остальные элементы (j, last) U [first, i) , правильно отсортированы, и в этом случае * j <= * i .

Рекурсивно разделите подозрительный диапазон пополам, пока не разделите его до одного элемента. Принимает O (log N) сравнений.

2
ответ дан 30 November 2019 в 10:39
поделиться
Другие вопросы по тегам:

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