Квадратичный алгоритм для 4-SUM

4-СУММА выглядит следующим образом:

Для данного массива из N различных целых чисел найдите 4 целых числа a, b, c, d, таких что a + b + c + d = 0.

Я мог бы придумать кубический алгоритм, использующий квадратичный алгоритм для задачи 3-SUM. Можем ли мы сделать лучше, чем кубический для 4-СУММ?

Ответ 1

Да, вы можете. Перейдите по всем парам чисел и сохраните их сумму (а также сохраните, какие числа дают эту сумму). После этого для каждой суммы проверьте, найдено ли ее отрицание среди сумм, которые у вас есть. Используя хэш, вы можете достичь квадратичной сложности, используя std:: map, вы достигнете O(n^2*log(n)).

EDIT: чтобы убедиться, что число не используется более одного раза, лучше хранить индексы вместо фактических чисел для каждой суммы. Также, поскольку заданная сумма может быть сформирована более чем одной парой, вам придется использовать хэш-мультимап. Имея в виду, что цифры различны для суммы X = a1 + a2, сумма -X может быть сформирована не более одного раза с использованием a1 и один раз с использованием a2, поэтому для данной суммы X вам нужно будет перебирать максимум 3 пары, давая -X как сумму. Это по-прежнему является постоянным.

Ответ 2

Для этой задачи также существует алгоритм O (N 2), использующий дополнительную память O (N 2).

  1. Сгенерируйте все попарные суммы в O (N 2) и сохраните пару (a i,j) в хеш-таблице и используйте абсолютное значение их суммы в качестве ключ хеш-таблицы (a i и j - два разных числа входного массива)

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

Есть альтернатива, если вы предпочитаете не использовать хеш-таблицу. Поскольку ваши числа являются целыми числами, вы можете отсортировать список всей суммы за линейное время элементов в списке сумм, используя что-то вроде Radix sort (есть O (N 2) элементов в список сумм).

Ответ 3

Для каждого индекса i и j добавьте S[i]+S[j] в multimap (multimap, потому что сумма может дублироваться из разных целых чисел) и проверьте, содержит ли multimap сумму -(S[i]+S[j]). Если это так, то добавьте к результирующему набору.

void fourSUM(vector<int> array)
{
unordered_set<vector<int>> result;   // set to avoid duplicate results 
multimap<int,pair<int,int>> twosum_map;

for(unsigned int i=0; i< array.size();i++)
{
    for(unsigned int j=i+1; j< array.size();j++)
    {
        // insert sum in multimap
        twosum_map.insert(make_pair(array[i]+array[j],make_pair(i,j)));

        // look for -ve sum in multimap
        int lookfor = -(array[i]+array[j]);
        std::pair <std::multimap<int,pair<int,int>>::iterator, std::multimap<int,pair<int,int>>::iterator> ret;
        ret = twosum_map.equal_range(lookfor);

        for(std::multimap<int,pair<int,int>>::iterator it = ret.first; it != ret.second; it++)
        {
            vector<int> oneresult;
            oneresult.push_back(array[i]);
            oneresult.push_back(array[j]);
            oneresult.push_back(array[it->second.first]);
            oneresult.push_back(array[it->second.second]);
            result.insert(oneresult); // this avoids duplicate results 
        }
    }
}


// Display Result 
for(set<vector<int>>::iterator it=result.begin();it != result.end();it++)
{
    for( vector<int>::const_iterator  vit = it->begin(); vit != it->end(); vit++)
    {
        cout << *vit << " ";
    }
    cout << endl;
}
}

Вставка/поиск в мультикарте - это log (n). Вставка в набор - log (n).

Сложность: O (n 2 * log (n)).