Re[2]: Задачки с Amazon SDE Interview
От: Sergei MO Россия  
Дата: 16.12.20 22:04
Оценка:
Придумал, как сделать ещё проще.

Если в ответе за числом X идёт число Y, то в исходной последовательности будет то же самое — за числом X всегда будет идти число Y.

Поэтому для решения задачи нам нужно посчитать количество вхождений каждого числа, и выяснить, идёт ли за ним всегда одно и то же число, или могут идти разные (конец последовательности трактуется как "идут разные числа").

Далее рассматриваем только числа, имеющие максимальное количество вхождений. По сути у нас есть ориентированный граф, вершины которого — числа, а дуги строятся по правилу: если за числом X всегда идёт число Y, то есть дуга X->Y. Ответом исходной задачи является самый длинный путь в этом графе. Поскольку исходящих дуг у каждой вершины не более одной, и отсутствуют циклы, то поиск такого пути тривиален.

И сложность решения теперь O(N*Log(N)).

  Код решения
#include <iostream>
#include <vector>
#include <stack>
#include <map>

using namespace std;

void solve(vector<int>& sequence)
{
    // для каждого числа считаем, сколько раз оно встречается
    // и одинаковые ли числа идут после него
    // если одинаковые - запоминаем их во втором поле, если разные - записываем -1
    map<int, pair<int, int>> numbers;
    for (size_t i = 0; i < sequence.size(); i++)
    {
        int nextNumber = i + 1 < sequence.size() ? sequence[i + 1] : -1;
        auto it = numbers.find(sequence[i]);
        if (it == numbers.end())
        {
            it = numbers.insert(make_pair(sequence[i], make_pair(1, nextNumber))).first;
        }
        else
        {
            it->second.first++;
            if (it->second.second != nextNumber)
            {
                it->second.second = -1;
            }
        }
    }

    int maxCount = 0;
    for (auto it = numbers.begin(); it != numbers.end(); ++it)
    {
        maxCount = it->second.first > maxCount ? it->second.first : maxCount;
    }

    // удаляем все числа, встречающиеся менее максимального числа раз
    // одновременно инициализируем поле счетчика для запоминания длины последовательности
    auto it = numbers.begin();
    while (it != numbers.end())
    {
        auto tmp = it++;
        if (tmp->second.first != maxCount)
        {
            numbers.erase(tmp);
        }
        else
        {
            tmp->second.first = -1;
        }
    }

    // поиск в глубину из каждого числа с кэшированием результата
    stack<int> stk;
    for (auto it = numbers.begin(); it != numbers.end(); ++it)
    {
        if (it->second.first == -1)
        {
            auto tmp = it;
            while (tmp->second.first == -1 && tmp->second.second != -1)
            {
                stk.push(tmp->first);
                tmp = numbers.find(tmp->second.second);
            }
            if (tmp->second.second == -1)
            {
                tmp->second.first = 0;
            }
            while (!stk.empty())
            {
                tmp = numbers.find(stk.top());
                tmp->second.first = numbers.find(tmp->second.second)->second.first + 1;
                stk.pop();
            }
        }
    }

    // ищем число, из которого начинается путь максимальной длины
    int maxLength = 0;
    int maxNumber = 0;
    for (auto it = numbers.begin(); it != numbers.end(); ++it)
    {
        if (it->second.first > maxLength)
        {
            maxLength = it->second.first;
            maxNumber = it->first;
        }
    }

    cout << "N = " << maxCount << endl;
    cout << maxNumber;
    it = numbers.find(maxNumber);
    while (it->second.second != -1)
    {
        it = numbers.find(it->second.second);
        cout << " " << it->first;
    }
    cout << endl;
}


int main()
{
    int arr[] = { 1, 2, 3, 4, 0, 4, 2, 3, 2, 3 };
    solve(vector<int>(arr, arr + sizeof(arr) / sizeof(int)));
    return 0;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.