@templatetypedef Если оба массива могут быть проиндексированы в позиции n в O (1), вы все равно вернетесь в квадрат с двумя массивами длины n.

жный дубликат:
Как найти k-й наименьший элемент в объединении двух отсортированных массивов?

Это вопрос, который один из моих друзей сказал мне, что он задавался во время интервью, я думал о решении.

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

 templatetypedef14 янв. 2011 г., 01:41
@ paxdiablo- Можете ли вы проверить мой ответ и посмотреть, что я что-то упустил? Я, кажется, получил это в O (LG ^ 2 N).
 paxdiablo14 янв. 2011 г., 01:29
Я не думаю, что это возможно, но я буду счастлив, что окажется неправым, поэтому это комментарий, а не ответ :-) Единственный способ сделать сам экстракт O (1) - объединить списки. который является O (n). В любом другом решении отсутствует жизненно важный бит информации о том, как целые числа распределяются между двумя списками, поэтому вам нужно проверить все значения в них (выше того, которое вы ищете) - это автоматически делает его O (n) линейно. Но я все же дам +1 за интересный вопрос.

Ответы на вопрос(5)

Решение Вопроса

A[0..n-1] а такжеB[0..n-1], который является O (log n).

Учитывая отсортированные массивы, вы знаете, чтоэнный самый большой появится где-то до или вA[n-1] если это в массивеA, или жеB[n-1] если это в массивеBРассмотреть предмет по индексуa вA и элемент в индексеb вB.Выполните бинарный поиск следующим образом (довольно грубый псевдокод, без учета разовых проблем):Еслиa + b > nзатем уменьшите поисковый набореслиA[a] > B[b] тогдаb = b / 2иначеa = a / 2Еслиa + b < n, а затем увеличить поисковый набореслиA[a] > B[b] тогдаb = 3/2 * bиначеa = 3/2 * a (на полпути междуa и предыдущийa)Еслиa + b = n тогдаэнный самый большойmax(A[a], B[b])

Я считаю, что в худшем случае O (ln n), но в любом случае определенно сублинейный.

 templatetypedef14 янв. 2011 г., 03:17
Метинкс, который вы не хотите увеличивать на 3/2. Я думаю, что вы, вероятно, хотите сделать, это просто стандартный двоичный поиск по обоим диапазонам, начинающимся в середине каждого и поддерживающий значения a_low, a_high и a_mid (плюс один для каждого для b). Я вернусь к вам, если это сработает.
 Captain Fogetti17 мар. 2016 г., 05:53
Не работает Учитывая массивы{3, 12, 13, 14, 21, 29, 35, 36, 38, 40, 41}; а также{-5, -3, 1, 5, 7, 9, 10, 11, 13, 14, 19}; попытка найти 5-й по величине элемент приведет к бесконечному циклу (или переполнению стека), поскольку первое условиеa + b > n будет правдой все время; даже когдаa уже 0, он будет продолжать входить вa = a / 2 ветка тем не менее. (Начальные индексы: A.length-1 и B.length-1)
 templatetypedef14 янв. 2011 г., 02:55
Мне очень нравится эта идея! У вас есть доказательство правильности? Я постараюсь выработать один, если вы этого не сделаете.
 John Kurlak22 сент. 2012 г., 16:40
Это не похоже на работу?
 Karoly Horvath17 сент. 2013 г., 17:12
Это не должно работать. только потому, что вы прибыли в точку, гдеa + b = n, это не значит, что n-й элемент есть. многие пары a, b удовлетворяют этому уравнению.

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

Так что я думаю, что здесь нет хитрости, начните со списка с меньшим начальным элементом и продвигайтесь, пока вы тоже:

Достигните n-го элемента, и все готово.Найти следующий элемент больше, чем следующий элемент в другом списке, после чего вы переключаетесь на другой список.Закончились элементы и переключи.
 biziclop14 янв. 2011 г., 01:47
Конечно, нет, но чтобы выбрать n-й элемент из списка любого размера, вы должны прочитать хотя бы n элементов.
 marcog14 янв. 2011 г., 01:44
-1 Бинарный поиск не читает каждый элемент.
 Apalala14 янв. 2011 г., 06:35
@templatetypedef Если оба массива могут быть проиндексированы в позиции n в O (1), вы все равно вернетесь в квадрат с двумя массивами длины n.
 templatetypedef14 янв. 2011 г., 01:49
@ biziclop- Если у вас есть отсортированный массив, вы можете выбрать n-й по величине в O (1), просто проиндексировав в позиции n.
 Nemo15714 янв. 2011 г., 04:10
Технически длясписок он прав, что чтение n-го элемента - это O (n), однако это использует сортировкумассивы которые O (1).
int[] a = new int[] { 11, 9, 7, 5, 3 };
int[] b = new int[] { 12, 10, 8, 6, 4 };
int n = 7;
int result = 0;
if (n > (a.Length + b.Length))
    throw new Exception("n is greater than a.Length + b.Length");
else if (n < (a.Length + b.Length) / 2)
{
    int ai = 0;
    int bi = 0;
    for (int i = n; i > 0; i--)
    {
        // find the highest from a or b
        if (ai < a.Length)
        {
            if (bi < b.Length)
            {
                if (a[ai] > b[bi])
                {
                    result = a[ai];
                    ai++;
                }
                else
                {
                    result = b[bi];
                    bi++;
                }
            }
            else
            {
                result = a[ai];
                ai++;
            }
        }
        else
        {
            if (bi < b.Length)
            {
                result = b[bi];
                bi++;
            }
            else
            {
                // error, n is greater than a.Length + b.Length
            }
        }
    }
}
else
{
    // go in reverse
    int ai = a.Length - 1;
    int bi = b.Length - 1;
    for (int i = a.Length + b.Length - n; i >= 0; i--)
    {
        // find the lowset from a or b
        if (ai >= 0)
        {
            if (bi >= 0)
            {
                if (a[ai] < b[bi])
                {
                    result = a[ai];
                    ai--;
                }
                else
                {
                    result = b[bi];
                    bi--;
                }
            }
            else
            {
                result = a[ai];
                ai--;
            }
        }
        else
        {
            if (bi >= 0)
            {
                result = b[bi];
                bi--;
            }
            else
            {
                // error, n is greater than a.Length + b.Length
            }
        }
    }
}
Console.WriteLine("{0} th highest = {1}", n, result);

ПозволятьFind( nth, A, B ) быть функцией, которая возвращает n-е число, и | A | + | B | > = н. Это простой псевдокод без проверки, является ли один из массивов маленьким, менее 3 элементов. В случае небольшого массива достаточно одного или двух бинарных поисков в большем массиве, чтобы найти нужный элемент.

Find( nth, A, B )
  If A.last() <= B.first():
    return B[nth - A.size()]
  If B.last() <= A.first():
    return A[nth - B.size()]
  Let a and b indexes of middle elements of A and B
  Assume that A[a] <= B[b] (if not swap arrays)
  if nth <= a + b:
    return Find( nth, A, B.first_half(b) )
  return Find( nth - a, A.second_half(a), B )

этоlog(|A|) + log(|B|)и потому что входные массивы могут быть сделаны, чтобы иметь n элементов каждыйlog(n) сложность.

что вы можете решить эту проблему, используя вариант бинарного поиска. Интуиция этого алгоритма заключается в следующем. Позвольте двум массивам быть A и B, и давайте для простоты предположим, что они имеют одинаковый размер (как вы увидите, в этом нет необходимости). Для каждого массива мы можем построить параллельные массивы Ac и Bc так, чтобы для каждого индекса i Ac [i] - это количество элементов в двух массивах, которые не больше, чем A [i], а Bc [i] - это число элементы в двух массивах, которые не больше, чем B [i]. Если бы мы могли эффективно построить эти массивы, то мы могли бы эффективно найти k-й наименьший элемент, выполнив бинарный поиск как по Ac, так и по Bc, чтобы найти значение k. Соответствующая запись A или B для этой записи является k-м по величине элементом. Бинарный поиск действителен, потому что два массива Ac и Bc отсортированы, в чем, я думаю, вы можете убедить себя довольно легко.

Конечно, это решение не работает в сублинейное время, потому что для построения массивов Ac и Bc требуется O (n) времени. Тогда возникает вопрос - есть ли способ, которым мы можемкосвенным образом построить эти массивы? То есть, мы можем определить значения в этих массивах, не обязательно создавая каждый элемент? ядумать что ответ да, используя этот алгоритм. Начнем с поиска в массиве A, чтобы узнать, имеет ли он k-е наименьшее значение. Мы точно знаем, что наименьшее k-е значение не может появиться в массиве в массиве A после позиции k (при условии, что все элементы различны). Итак, давайте сосредоточимся только на первых k элементах массива A. Мы выполним бинарный поиск по этим значениям следующим образом. Старт в позиции к / 2; это k / 2-й наименьший элемент в массиве A. Теперь выполните двоичный поиск в массиве B, чтобы найти наибольшее значение в B, которое меньше этого значения, и посмотрите на его положение в массиве; это количество элементов в B меньше текущего значения. Если мы сложим положение элементов в A и B, у нас будет общее количество элементов в двух массивах меньше, чем текущий элемент. Если это точно к, мы сделали. Если это меньше, чем k, то мы рекурсируем в верхней половине первых k элементов A, а если это больше, чем k, мы рекурсируем в нижней половине первых элементов k и т. Д. В конце концов, мы либо найдите, что k-й по величине элемент находится в массиве A, и в этом случае мы закончили. В противном случае повторите этот процесс для массива B.

Время выполнения для этого алгоритма заключается в следующем. Поиск в массиве A выполняет двоичный поиск по k элементам, что занимает O (lg k) итераций. Каждая итерация стоит O (lg n), так как мы должны выполнить двоичный поиск в B. Это означает, что общее время для этого поиска составляет O (lg k lg n). Время, чтобы сделать это в массиве B, то же самое, поэтому чистое время выполнения алгоритма O (lg k lg n) = O (lg2 n) = o (n), что является сублинейным.

 templatetypedef11 авг. 2015 г., 09:11
(log n) ^ 2 не мало-мало из log n - оно растет асимптотически быстрее - но оно мало из n.
 Hengameh11 авг. 2015 г., 09:09
Ваша последняя строка должна быть: O (lg k lg n) = O (lg2 ​​n) = o (logn), что является сублинейным.
 Nemo15714 янв. 2011 г., 02:46
Это звучало достаточно интересно, я должен был попробовать это:gist.github.com/779003
 biziclop14 янв. 2011 г., 11:17
Просто небольшое добавление: вам не нужно искать по всему массиву B либо, если бинарный поиск берет вас строго выше или ниже индекса k / 2, вы уже знаете ответ, является ли сумма больше k.

Ваш ответ на вопрос