Самый большой элемент в массиве Разделяй и властвуй O (N.log (N))

Говорят, что массив a [], содержащий N элементов, допускающих повторение, «содержат в основном элементы av», если более половины его содержимого равно v. Учитывая массив a [], он предназначен для построения эффективного алгоритма (в то время как N.log(N) и используя принцип «разделяй и властвуй»), чтобы проверить, содержит ли он элемент большинства, и определить его. Рассмотрим единственную доступную операцию сравнения между элементами массива, это равенство (a[i] == a[j]), выполняемую за константное время. (Подсказка: в алгоритме разделите массив на [] на два подмассива a1 [] и a2 [], каждый из которых имеет половину размера []. Если элемент в большей части [] равен v, то v должен быть также элемент в большинстве a1 [], или a2 [] или обоих).

int main() {

    int a[12] = {5, 9, 3, 13, 5, 21, 5, 7, 17, 12, 5, 6};
    int N = 12, lo = 0, hi = N - 1, mid,i,j;

    mid = lo + (hi - lo) / 2;
    int n1 = mid - lo + 1;
    int n2 =  hi - mid;
    int a1[n1],a2[n2];

    /* Copy data to temp arrays a1[] and a2[] */
    for (i = 0; i < n1; i++)
        a1[i] = a[lo + i];
    for (j = 0; j < n2; j++)
        a2[j] = a[mid+1+j];


    while (i < n1 && j < n2) {

        if(a1[i]==a2[j]){

        }else if(){


        }else{


        }

    }
    return 0;
}

У меня возникли проблемы с тем, как я должен продолжить, используя операцию равенства, сравнивая вспомогательные массивы, чтобы увидеть, находится ли самый элемент на a1 [] или a2 [] или на обоих!


person CodeOnce    schedule 02.02.2018    source источник
comment
@AlbinPaul Кажется, OP не разрешено сортировать. Он не может использовать другие сравнения, кроме равенства.   -  person kyriakosSt    schedule 02.02.2018
comment
Если элемент в большей части a [] равен v, то v также должен быть элементом в большинстве a1 [], или a2 [] или обоих. Однако обратный вывод неверен: даже если v является большинством, например. a1[] это не обязательно должно быть большинство в a[].   -  person JimmyB    schedule 02.02.2018
comment
Является ли D-и-C требованием? Есть линейный алгоритм.   -  person user58697    schedule 02.02.2018


Ответы (3)


Вот реализация Python, которая подходит под описание (извините, я не разбираюсь в C, но я думаю, что это довольно простой код). Мы можем следить за зарегистрированными возвращаемыми значениями и индексами для каждого проверяемого раздела, чтобы понять, как это работает.

# Returns v if v is a majority;
# otherwise, returns None
def f(arr, low, high):
  if low == high:
    return arr[low]

  if low + 1 == high:
    return arr[low] if arr[low] == arr[high] else None

  n = high - low + 1
  mid = (low + high) / 2

  l = f(arr, low, mid)
  r = f(arr, mid + 1, high)

  print 'n: ' + str(n) + '; l: ' + str(l) + '; r: ' + str(r) + '; L: ' + str((low, mid)) + '; R: ' + str((mid + 1, high))

  if l == r:
    return l

  counts = [0, 0]

  for i in xrange(low, high + 1):
    if arr[i] == l:
      counts[0] = counts[0] + 1
    if arr[i] == r:
      counts[1] = counts[1] + 1

  if l and counts[0] * 2 > n:
    return l

  if r and counts[1] * 2 > n:
    return r

  return None

Вывод:

a = [5, 9, 3, 5, 5, 21, 5, 7, 17, 5, 5, 5]

print f(a, 0, len(a) - 1)

"""
n: 3; l: None; r: 3; L: (0, 1); R: (2, 2)
n: 3; l: 5; r: 21; L: (3, 4); R: (5, 5)
n: 6; l: None; r: 5; L: (0, 2); R: (3, 5)
n: 3; l: None; r: 17; L: (6, 7); R: (8, 8)
n: 3; l: 5; r: 5; L: (9, 10); R: (11, 11)
n: 6; l: None; r: 5; L: (6, 8); R: (9, 11)
n: 12; l: None; r: 5; L: (0, 5); R: (6, 11)
5
"""
person גלעד ברקן    schedule 02.02.2018

Я думаю, что функция должна:

1) Рекурсивно вызывать себя для первой половины массива (возвращает ответ a)

2) Рекурсивно вызывать себя для второй половины массива (возвращает ответ b)

3) Прокрутите массив и подсчитайте, сколько совпадений a/b, и верните тот, который имеет наибольшее количество совпадений.

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

person Peter de Rivaz    schedule 02.02.2018
comment
Я думаю, что ваше описание как есть вернет 1 для ввода 1, 1, 1, 2, 2, 3. Но 1 - это не большинство. - person גלעד ברקן; 02.02.2018
comment
Ставлю минус, пока не исправите :) - person גלעד ברקן; 03.02.2018

Вероятно, это не тот ответ, который вы ищете. Но есть интересный вероятностный подход к этой проблеме. Вы можете выбрать определенную позицию x в массиве и подсчитать количество вхождений массива [x], чтобы проверить, появился ли он >= array.size() / 2.

Если есть элемент, который заполняет более половины массива, то вероятность случайного выбора его положения составляет> 1/2 для каждой итерации.

Таким образом, если вы делаете что-то вроде 30 итераций, вероятность выбора «доминирующего» элемента составляет (1 - (1/2) ^ 30), что подходит почти для любого приложения.

Сложность O (число итераций * размер массива)

Вот код (:.

Он написан на C++, но могу поспорить, что вы без особых усилий сможете перевести его на C.

#include <vector>
#include <iostream>


int arraySize, numberOfIterations;

int count(int element, std::vector<int>& array)
{
    int count = 0;
    for(const int& number : array)
    {
        count += (number == element);
    }
    return count;
}


int main(){

    srand(time(0));

    std::cin >> arraySize;
    std::vector<int> arr(arraySize);

    for(int i = 0; i < arraySize; ++i)
    {
        std::cin >> arr[i];
    }

    std::cin >> numberOfIterations;

    for(int i = 0; i < numberOfIterations; ++i)
    {
        int idx = rand() % arraySize;
        int freq = count(arr[idx], arr);
        //std::cout << idx << std::endl;
        if(freq > arraySize / 2)
        {
            std::cout << "The element = " << arr[idx] << " dominates the array provided " << std::endl;
            return 0;
        }
    }
    return 0;
}
person Francisco Geiman    schedule 02.02.2018