Как найти k-е наибольшее число в двух отсортированных массивах разного размера

Это тот же вопрос, что и Алгоритм поиска n-го по величине числа в двух массивах размера n, ЗА ИСКЛЮЧЕНИЕМ того, что два отсортированных массива имеют разные размеры.

Я попытался реализовать вариант алгоритма, аналогичный предложенному для решения моей задачи, но не могу показать его правильность. Похоже, что для k = 6 он не работает. Возвращаемая пара — это индексы для list1 и list2 соответственно, когда алгоритм завершает работу.

#include <iostream>
#include <utility>

using namespace std;

pair<int, int> smallestKElements(int list1[], int list2[], int k) {

// TODO: pass in the array sizes as parameters 
int m = 8; 
int n = 5;

// initialize array pointers such that i + j = k
int i = m/2;
int j = n/2; 
if (i + j + 2 < k) {
    while (i + j + 2 != k) {
        if (++i + j + 2 == k)
            break;
        if (i + ++j + 2 == k)
            break;
    }
} else if (i + j + 2 > k) {
    while (i + j + 2 != k) {
        if (--i + j + 2 == k)
            break;
        if (i + --j + 2 == k)
            break;
    }
}

// step forward in one array and step backward in another array
// decrement step size with every iteration until it is 0
int s = k/2; 
while (s > 0) {
    if (list1[i] < list2[j]) {
        if (m - 1 - i >= s &&
            j >= s) {

            i += s;
            j -= s;
        }
    } else {
        if (i >= s &&
            n - 1 - j >= s) {

            i -= s;
            j += s;
        }
    }
    s = s/2;
}

pair<int, int> r(i,j);
return r;
}

int main() {

int list1[] = {1, 4, 6, 7, 10, 11, 13, 27};
int list2[] = {2, 3, 20, 40, 60};

pair<int, int> test = smallestKElements(list1, list2, 6);
cout << test.first << "," << test.second << endl;

return 0;
}

person allenylzhou    schedule 23.05.2014    source источник
comment
Можете ли вы добавить текстовое объяснение вашего алгоритма? Я еще не полностью переварил его, но он не похож на то, что я бы использовал.   -  person M.M    schedule 23.05.2014
comment
Чтобы исправить ваш TODO, держите элементы в vector<int> вместо массива в стиле C.   -  person M.M    schedule 23.05.2014
comment
Обратите внимание, что хотя принятый ответ в связанном дубликате кажется не совсем правильным, похоже, что ответ lambdapilgrim верен, включая работу с массивами неравной длины (и ответ JF Sebastian показывает реализацию этого алгоритма на С++).   -  person Jerry Coffin    schedule 23.05.2014
comment
lambdapilgrim, кажется, имеет правильный ответ. Я попытался решить проблему, выполнив параллельный двоичный поиск в обоих массивах, но когда массивы имеют неравную длину, инвариант цикла i + j = k не выполняется, поэтому этот подход не работает.   -  person allenylzhou    schedule 23.05.2014


Ответы (1)


Хорошо, вы могли бы сделать что-то подобное для каждого списка, если бы я понял вашу проблему:

std::nth_element(lst, lst + k, begin(lst) + list_size, std::greater<int>());

Имейте в виду, что вам нужен размер списка. Вы можете сделать то же самое с другим массивом. Это изменит массивы, если вы не хотите изменять массивы, создайте массивы из std::reference_wrapper и nth_element.

person Germán Diago    schedule 23.05.2014
comment
Меня интересует реализация. - person allenylzhou; 23.05.2014
comment
На самом деле, я не уверен, что правильно отвечаю на ваш вопрос. Вам нужен n-й по величине элемент, ищущий в обоих массивах. Или самый большой в каждом массиве? - person Germán Diago; 23.05.2014
comment
Если то, что вы хотите, это сырая реализация, это слишком много работы сейчас. Я на работе, в данный момент не могу вам помочь. - person Germán Diago; 23.05.2014
comment
Реализация сортирует элементы и помещает элемент, который будет на n-й позиции, с помощью компаратора. В этом случае все элементы перед этим элементом больше или равны n-му элементу. Все, что идет после, меньше n-го элемента. - person Germán Diago; 23.05.2014
comment
Я ищу n-й по величине элемент, глядя на оба массива. - person allenylzhou; 23.05.2014
comment
В обоих одновременно? - person Germán Diago; 23.05.2014