В: Можно ли считать пары массивов с побитовым И > k ~ лучше, чем O(N^2)?

Дан массив nums

Считать нет. пар (два элемента), где побитовое И больше, чем K

Грубая сила

for i in range(0,n):
   for j in range(i+1,n):
       if a[i]&a[j] > k:
           res += 1

Лучшая версия: предварительная обработка для удаления всех элементов ≤k а потом грубая сила

Но мне было интересно, каков будет предел сложности здесь?

Можем ли мы добиться большего успеха с подходом trie, hashmap, например с двумя суммами?

(Я не нашел эту проблему на Leetcode, поэтому решил спросить здесь)

Могут ли какие-либо элементы массива быть отрицательными? Если это так, вы не должны удалять их, например, в 16 битах 0xffff и 0x7fff равны 0x7fff.

dmuir 25.12.2020 10:34

@yozaam: Источник этого вопроса, пожалуйста?

Shridhar R Kulkarni 26.12.2020 18:21

@ShridharRKulkarni зайдите на канал #interview-experience, кто-то поделился им в предпоследнем сообщении, которое они получили по ссылке на веб-сайт онлайн-оценки: http://binarysearch.com/

yozaam 30.12.2020 05:33

@dmuir Я не думал об этом, хорошо!

yozaam 30.12.2020 05:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
5
1 410
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Пусть size_of_input_array = N. Пусть входной массив состоит из B-битных чисел

Вот простое для понимания и реализации решение.

  • Удалите все значения <= k.

  • На изображении выше показаны 5 10-битных чисел.

Шаг 1: График смежности

  • Сохраните список установленных битов. В нашем примере 7-й бит установлен для чисел с индексами 0,1,2,3 во входном массиве.

Шаг 2: Задача состоит в том, чтобы избежать повторного подсчета одних и тех же пар.

Чтобы решить эту проблему, мы воспользуемся структурой данных union-find, как показано в коде ниже.

//unordered_map<int, vector<int>> adjacency_graph;
//adjacency_graph has been filled up in step 1

vector<int> parent;
for(int i = 0; i < input_array.size(); i++)
    parent.push_back(i);

int result = 0;
for(int i = 0; i < adjacency_graph.size(); i++){ // loop 1
    auto v = adjacency_graph[i];
    if (v.size() > 1){
        int different_parents = 1;
        for (int j = 1; j < v.size(); j++) { // loop 2
            int x = find(parent, v[j]);
            int y = find(parent, v[j - 1]);
            if (x != y) {
                different_parents++;
                union(parent, x, y);
            }
        }
        result += (different_parents * (different_parents - 1)) / 2;
    }
}
return result;

В приведенном выше коде find и union взяты из структуры данных union-find.

Сложность времени:

Шаг 1:

Build Adjacency Graph: O(BN)

Шаг 2:

Loop 1: O(B)
Loop 2: O(N * Inverse of Ackermann’s function which is an extremely slow-growing function) 

Общая временная сложность

= O(BN)

Космическая сложность

Overall space complexity = O(BN)

«остальная часть проста» - это не то, что ищет OP. Кроме того, это не так просто, как вы думаете, так что объясните, пожалуйста.

Abhinav Mathur 25.12.2020 12:30

@גלעדברקן Где-то я сомневался, что логика родительского массива будет работать постоянно. Я изменил его, чтобы использовать union-find. Помогите мне с временной сложностью. Я предполагаю, что в нашем случае Inverse Ackermann будет амортизировать тета (1).

Shridhar R Kulkarni 26.12.2020 18:18

Я хочу, чтобы за это решение была предложена награда. Довольно тяжелая работа. 😛

Shridhar R Kulkarni 26.12.2020 18:21

Спасибо, @ShridharRKulkarni, как мне назначить награду?

yozaam 30.12.2020 05:38

@yozaam: У тебя большой ♥️. Спасибо! Сохраните свою репутацию на ранних стадиях SO. Помогает зарабатывать привилегии и вносить свой вклад в SO лучше.

Shridhar R Kulkarni 30.12.2020 06:13

Не могли бы вы добавить тестируемый код со случайным вводом? (Или даже просто тестируемый код). Основываясь на комментарии Дэвида Эйзенстата , я не уверен, что верю, что это (или, по крайней мере, временная сложность, которую вы предлагаете) возможно.

גלעד ברקן 31.12.2020 03:35

Мне любопытно узнать о вашей обеспокоенности, а также о комментарии Дэвида. Хотя у меня мало времени. Вы или @yozaam можете протестировать код и сообщить о любых неудачных случаях. Пожалуйста, используйте С++. Теоретически решение выглядит хорошо. Буду продолжать работу, если будут сбои. Кроме того, мы можем начать чат вместе с Дэвидом, чтобы понять его комментарий. Если вы понимаете комментарий полностью, пожалуйста, помогите мне понять его тоже. Я очень хочу узнать об этом.

Shridhar R Kulkarni 31.12.2020 04:04

@ גלעדברקן Я не вижу, где в этом ответе используется k за пределами шага обрезки. Предполагая отсутствие ограничений на размер слова (что могло бы обойти SETH с помощью упомянутой мной техники суммирования по подмножествам), мы можем просто выделить уникальный старший бит для каждого входного числа и сделать шаг сокращения неактуальным (поскольку все числа будут ≥ k, но будет иметь то же побитовое И, что и раньше). Учитывая, что остальная часть алгоритма кажется независимой от k, мне трудно поверить, что он правильный. +1 к запросу кода.

David Eisenstat 31.12.2020 04:26

Это становится интересным. На выходных буду кодить. Между тем, если кто-то может написать это на C++, это было бы здорово.

Shridhar R Kulkarni 31.12.2020 05:05

Обновление: я мог бы потратить некоторое время на написание кода. pastebin.com/TspKFyj7 Я нашел ошибку для ввода, который я упомянул в коде. Я пытаюсь это исправить. Проблема заключается в проверке битов <= (int)(log2(k)). Было бы здорово, если бы кто-то мог потратить некоторое время на обдумывание этой интересной ошибки, и я тоже попробую, когда и когда позволит время. Спасибо за ваше терпение. Я также думаю о возможности каких-либо альтернативных решений.

Shridhar R Kulkarni 03.01.2021 12:44

Во-первых, обрезать все <= k. Также отсортируйте список значений.

Переходя от старшего бита к младшему, мы собираемся отслеживать набор чисел, с которыми мы работаем (изначально все s=0, e=n).

Пусть p будет первой позицией, содержащей 1 в текущем наборе в текущей позиции.

Если бит в k равен 0, то все, что дает 1 мир, определенно будет хорошим, и нам нужно исследовать те, которые получают 0. У нас есть (end - p) * (end-p-1) /2 пар в текущем диапазоне и (end-p) * <total 1s in this position larger or equal to end> комбинаций с большими ранее хорошими числами, которые мы можно добавить в решение. Для продолжения обновляем end = p. Мы хотим посчитать единицы во всех приведенных выше числах, потому что раньше мы считали их только парами друг с другом, а не с такими младшими числами в наборе.

Если бит в k равен 1, то мы еще не можем подсчитать выигрыши, но нам нужно исключить все, что ниже p, поэтому мы обновляем start = p.

Вы можете остановиться, как только вы прошли все биты или start==end.

Подробности:

  • Поскольку на каждом шаге мы удаляем либо все, что имеет 0, либо все, что имеет 1, то все между началом и концом будет иметь один и тот же битовый префикс. поскольку значения отсортированы, мы можем выполнить бинарный поиск, чтобы найти p.
  • Для <total 1s in this position larger than p>. У нас уже есть отсортированные значения. Таким образом, мы можем вычислить частичные суммы и сохранить для каждой позиции в отсортированном списке количество единиц в каждой битовой позиции для всех чисел над ней.

Сложность:

  • Мы получили побитно, поэтому L (битовая длина чисел), мы выполняем двоичный поиск (logN), а также поиск и обновление O (1), так что это O (L logN).
  • Нам нужно отсортировать O(NlogN).
  • Нам нужно вычислить частичные побитовые суммы O(L*N).

Всего O(L logN + NlogN + L*N).

Поскольку N>>L, L logN включается в NlogN. Поскольку L>>logN (вероятно, у вас есть 32-битные числа, но их не 4 миллиарда), то NlogN включается в L*N. Таким образом, сложность составляет O (L * N). Поскольку нам также нужно сохранять частичные суммы вокруг памяти, сложность также составляет O (L * N).

Другие вопросы по теме