Два элемента в массиве, чье значение является максимальной

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

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

кроме этого ,есть ли эффективный алгоритм?

6 ответов


Я думаю, что у меня есть алгоритм O(N lg U) для этого, где U-наибольшее число. Идея похожа на user949300, но с немного более подробно.

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

такой алгоритм следует. Начните с поиска самого высокого 1 бита в любом месте чисел(вы можете сделать это за время O(N lg U), выполнив работу O (lg U) для каждого из n чисел). Теперь разделите массив на две части - одно из чисел, имеющих 1 в этом бите, и группу с 0 в этом бите. Любое оптимальное решение должно сочетать число с 1 в первом месте с числом с 0 в этом месте, так как это поставило бы 1 бит как можно выше. Любое другое сопряжение имеет 0.

теперь, рекурсивно мы хотим найти спаривание чисел из группы 1 и 0, которая имеет наибольшее 1 в них. Для этого из этих двух групп разделите их на четыре группы:--5-->

  • числа, начинающиеся с 11
  • числа, начиная с 10
  • номера, начинающиеся с 01
  • номера, начинающиеся с 00

если есть какие-либо числа в группе 11 и 00 или в группах 10 и 01, их XOR будет идеальным (начиная с 11). Следовательно, если любая из этих пар групп не пуста, рекурсивно вычислите идеальное решение из этих групп, а затем верните максимум этих решений подзадачи. В противном случае, если обе группы пусты, это означает, что все числа должны иметь одну и ту же цифру во второй позиции. Следовательно, оптимальный XOR числа, начинающегося с 1, и числа, начинающегося с 0, в конечном итоге будет иметь следующий второй бит, поэтому мы должны просто посмотреть на третий немного.

это дает следующий рекурсивный алгоритм, который, начиная с двух групп чисел, разбитых на их MSB, дает ответ:

  • данная группа 1 и группа 0 и битовый индекс i:
    • если битовый индекс равен количеству битов, верните XOR (уникального) числа в группе 1 и (уникального) числа в группе 0.
    • строительство группы 11, 10, 01 и 00 из этих групп.
    • если группа 11 и группа 00 непустая, рекурсивно найти максимальный XOR этих двух групп, начиная с бита i + 1.
    • если группа 10 и группа 01 непусты, рекурсивно найдите максимальный XOR этих двух групп, начиная с бита i + 1.
    • если любая из вышеуказанных пар была возможна, то верните максимальную пару, найденную рекурсией.
    • в противном случае все числа должны иметь один и тот же бит в позиции i, поэтому верните максимальную пару, найденную, посмотрев бит i + 1 на групп 1 и 0.

чтобы начать алгоритм, вы можете просто разделить числа из начальной группы на две группы - числа с MSB 1 и числа с MSB 0. Затем вы запускаете рекурсивный вызов вышеуказанного алгоритма с двумя группами чисел.

в качестве примера рассмотрим цифры 5 1 4 3 0 2. У них есть представления

101  001  100   011   000   010

мы начнем с разделения их на 1 группу и 0 группа:

101  100
001  011  000  010

теперь мы применяем этот алгоритм. Мы разбить на группы 11, 10, 01, и 00:

11:
10:  101  100
01:  011  010
00:  000  001

теперь мы не можем пару каких 11 элементов с 00 элементы, поэтому мы просто рекурсия на 10 и 01 групп. Это означает, что мы строим группы 100, 101, 010 и 011:

101: 101
100: 100
011: 011
010: 010

теперь, когда мы дошли до ведер с одним элементом в них, мы можем просто проверить пары 101 и 010 (что дает 111) и 100 и 011 (что дает 111). Любой вариант работает здесь, поэтому мы получаем, что оптимальный ответ-7.

давайте подумаем о времени работы данного алгоритма. Обратите внимание, что максимальная глубина рекурсии O(lg U), так как в числах есть только o(log U) бит. На каждом уровне дерева каждое число появляется ровно в одном рекурсивном вызове, и каждый из рекурсивных вызовов работает пропорционально общему числу чисел в группах 0 и 1, потому что нам нужно распределить их по битам. Следовательно, есть O (log U) уровни в дереве рекурсии, и каждый уровень выполняет O(n) работу, давая общую работу O (N log U).

надеюсь, что это помогает! Это была потрясающая проблема!


игнорируя бит знака, одно из значений должно быть одним из значений с наибольшим значащий бит. Если все значения не имеют этот бит set в этом случае вы переходите на следующий высокий, что не во всех значениях. Таким образом, вы можете сократить возможности для 1-го значения, посмотрев на HSB. Например, если возможности

0x100000
0x100ABC
0x001ABC
0x000ABC

1-е значение максимальной пары должно быть 0x100000 или 0x10ABCD.

@внутренняя ошибка сервера я не думаю, что маленький верна. У меня нет отличной идеи для сокращения 2-го значения. Просто любое значение не в списке возможных значений 1st. В моем примере 0x001ABC или 0x000ABC.


это можно решить в O(NlogN) сложность времени с помощью Trie.

  • построить trie. Для каждого целочисленного ключа каждый узел trie будет содержать каждый бит (0 или 1), начиная с самого значительного бита.
  • теперь для каждого arr[i] элемент arr[0, 1, ..... N]
    • выполнить запрос, чтобы получить максимальное значение xor для arr[i]. Мы знаем xor различных типов битов (0 ^ 1 или 1 ^ 0) всегда 1. Так во время запроса каждый бит, попробуйте пересечь узел, удерживающий противоположный бит. Это сделает этот конкретный бит 1 результат в максимизации значения xor. Если нет узла с противоположным битом, только тогда пересеките тот же битовый узел.
    • после запроса вставить arr[i] в trie.
    • для каждого элемента следите за максимально возможным значением Xor.
    • во время обхода каждого узла создайте другой ключ, для которого XOR максимизируется.

на N элементы, нам нужен один запрос(O(logN)) и вставки(O(logN)) для каждого элемента. Таким образом, общая сложность времени O(NlogN).

вы можете найти хорошее наглядное объяснение того, как это работает в этой теме.

вот реализация c++ вышеуказанного алгоритма:

const static int SIZE = 2;
const static int MSB = 30;
class trie {
private:
    struct trieNode {
        trieNode* children[SIZE];
        trieNode() {
            for(int i = 0; i < SIZE; ++i) {
                children[i] = nullptr;
            }
        }
        ~trieNode() {
            for(int i = 0; i < SIZE; ++i) {
                delete children[i];
                children[i] = nullptr;
            }
        }
    };
    trieNode* root;
public:
    trie(): root(new trieNode()) {
    }
    ~trie() {
        delete root;
        root = nullptr;
    }

    void insert(int key) {
        trieNode* pCrawl = root;
        for(int i = MSB; i >= 0; --i) {
            bool bit = (bool)(key & (1 << i));
            if(!pCrawl->children[bit]) {
                pCrawl->children[bit] = new trieNode();
            }
            pCrawl = pCrawl->children[bit];
        }
    }

    int query(int key, int& otherKey) {
        int Xor = 0;
        trieNode *pCrawl = root;
        for(int i = MSB; i >= 0; --i) {
            bool bit = (bool)(key & (1 << i));
            if(pCrawl->children[!bit]) {
                pCrawl = pCrawl->children[!bit];
                Xor |= (1 << i);
                if(!bit) {
                    otherKey |= (1 << i); 
                } else {
                    otherKey &= ~(1 << i);
                }
            } else {
                if(bit) {
                    otherKey |= (1 << i); 
                } else {
                    otherKey &= ~(1 << i);
                }
                pCrawl = pCrawl->children[bit];
            }
        }
        return Xor;
    }
};

pair<int, int> findMaximumXorElements(vector<int>& arr) {
    int n = arr.size();
    int maxXor = 0;
    pair<int, int> result; 
    if(n < 2) return result;
    trie* Trie = new trie();
    Trie->insert(0); // insert 0 initially otherwise first query won't find node to traverse
    for(int i = 0; i < n; i++) {
        int elem = 0;
        int curr = Trie->query(arr[i], elem);
        if(curr > maxXor) {
            maxXor = curr;
            result = {arr[i], elem};
        }
        Trie->insert(arr[i]);
    }
    delete Trie;
    return result;
}

очень интересная проблема! Вот моя идея:

  • сначала создайте двоичное дерево из всех чисел, используя двоичный представление и сортировка их в дерево самый значительный бит сначала (добавьте ведущие нули, чтобы соответствовать самому длинному числу). Когда каждый путь от корня до любого листа представляет одно число от оригинала набор.
  • пусть A и b-указатели на узел дерева и инициализируют их в корне.
  • Теперь переместите a и b вниз по дереву, попытка использовать противоположные ребра на каждом шаге, т. е. если a движется вниз по 0-краю, b движется вниз по 1-краю, если это невозможно.

Если a и b достигают листа, он должен указывать на два числа с" очень немногими " одинаковыми битами.

Я только что придумал этот алгоритм и не знаю, правильно ли это или как это доказать. Однако это должно быть во время o(n).


сделать рекурсивную функцию, которая принимает два списка целых чисел, A и B, в качестве своих аргументов. В качестве возвращаемого значения он возвращает два целых числа, одно из A и одно из B, которые максимизируют XOR двух. Если все числа равны 0, возвращает (0,0). В противном случае функция выполняет некоторую обработку и вызывает себя рекурсивно дважды, но с меньшими целыми числами. В одном из рекурсивных вызовов он рассматривает взятие целого числа из списка A для предоставления 1 в бит k, а в другом вызове он рассматривает взятие целое число из списка B для предоставления от 1 до бита k.

У меня нет времени сейчас, чтобы заполнить детали, но, может быть, этого будет достаточно, чтобы увидеть ответ? Кроме того, я не уверен, что время выполнения будет лучше, чем N^2, но это, вероятно, будет.


мы можем найти максимальное число в o (n) времени, а затем цикл через массив, выполняющий xor с каждым элементом. Предполагая, что стоимость операции xor равна O(1), мы можем найти max xor двух чисел в o (n) времени.