Придумал, как сделать ещё проще.
Если в ответе за числом 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;
}
|
| | |