#c #algorithm #vector
#c #алгоритм #вектор
Вопрос:
Я видел следующий вопрос, хотя мне удалось решить его в O (n ^ 2), я думаю, мы можем добиться большего.
Заданный вектор целых чисел возвращает максимальное количество несмежных копий аналогичного числа.
Например, дано: [9,2,3,4,0,4,5,6,0,8]
мы видим, что у нас есть 2 несмежных 0 и 2 несмежных 4 (остальные — единицы), поэтому ответ max (2,2) = 2;
дано: [4,4,4,4,4]
у нас есть 3 несмежных 4, поэтому ответ равен 3. мы берем сначала 4, затем мы не можем взять соседний с ним (они соседние), поэтому мы берем следующий и так далее.
Мое решение: выполните итерацию по вектору и проверьте, сколько несмежных копий мы видим из текущего числа, если оно больше текущего максимума, мы соответствующим образом обновляем max.
Вопрос: Как мы можем решить это более эффективно?
Комментарии:
1. В чем вопрос?
2. Извините, если я не понял, сказав: «Я думаю, мы можем сделать лучше». можно ли это решить более эффективно?
3.
map<int,int> counts; for i in 0 to size: if v[i] is different than v[i - 1] then counts[v[i]] ; return max entry in counts
4. @Jeffrey может быть, я неправильно понимаю, но разве это не приводит к результату 1 вместо 3 для
[4,4,4,4,4]
?5. да, я имел в виду, для всего значения, если оно отличается от предыдущего или если вы пропустили предыдущий, потому что это не был другой счетчик приращения
Ответ №1:
Если вас устраивает использование O (n) пространства, вы можете использовать сегменты для значений, которые вы видите, для достижения O (n) времени выполнения.
Самый простой способ реализовать это с помощью map. ie:
std::pair<int, int> max_adj(std::vector<int> arr) {
std::map<int, int> buckets;
for(int x = 0; x < arr.size(); x ) {
// Loop to eat up adjacent values
int in_a_row = 1;
for(int curr = x ;
x < arr.size() amp;amp; arr[curr] == arr[x];
x , in_a_row ) { }
x--; // The loop will increment x one past last dupe, so go back
// Only count every other adjacent value seen
buckets[arr[x]] = (in_a_row 1) / 2;
}
// Find the most seen
std::map<int, int>::iterator mx = std::max_element
(
buckets.begin(), buckets.end(),
[] (const std::pair<int, int> amp;p1, const std::pair<int, int> amp;p2) {
return p1.second < p2.second;
}
);
if(mx != buckets.end()) {
return *mx;
}
return std::pair<int, int>(-1, -1);
}
Живой пример: https://ideone.com/v9OOIA
Комментарии:
1.
std::max_element
может возвращать что-то, что вы не можете разыменовать, еслиarr.size() is 0
2. С
[1 2 1 1]
помощью, вы получите ответ 1, если я хорошо понимаю ваш алгоритм. Я ожидал ответа 2, но я не уверен, что либо понимаю проблему!3. @Джефф хороший звонок. Я отредактировал, чтобы покрыть это. Спасибо!
4. @Damien из моего понимания проблемы, это правильно.
1
должно быть подсчитано дважды: один раз для индекса 0 и один раз для индекса 2 (но не для индекса 3!)
Ответ №2:
Эта проблема может быть решена путем создания массива, который содержит число и его индекс, как показано ниже,
исходный массив = [9, 2, 3, 4, 0, 4, 5, 6, 0, 8]
,
числовой индексный массив = [ 9
, 0], [ 2
, 1], [ 3
, 2], [ 4
, 3], [ 0
, 4], [ 4
, 5], [ 5
, 6], [ 6
, 7], [ 0
, 8], [ 8
, 9]
Здесь первый элемент std::pair
— это само число, а второй элемент — индекс числа.
После этого отсортируйте этот массив по числам, и результат будет следующим,
[ 0
, 8], [ 0
, 4], [ 2
, 1], [ 3
, 2], [ 4
, 5], [ 4
, 3],[ 5
, 6], [ 6
, 7], [ 8
, 9], [ 9
, 0]
Цель сортировки — привести одинаковые числа рядом друг с другом. Как только одинаковые числа оказываются смежными, для поиска ответа требуется простая итерация. Давайте посмотрим, как это работает,
Первое число в отсортированном массиве 0
и при нахождении upper bound
0
даст все смежные 0
, это означает, что будут доступны следующие,
[ 0
, 8], [ 0
, 4]
Но, как вы можете видеть выше, эти записи расположены не в порядке индекса, запись индекса 4
следует за записью индекса 8
, и это потому std::sort
, что не являетсястабильная сортировка, это означает, что относительный порядок элементов не сохраняется. Поэтому, прежде чем продолжить, эти элементы должны быть снова отсортированы по индексу, и результат будет
[ 0
, 4], [ 0
, 8]
, Как показано выше, индексируют 4
и 8
не являются смежными 4 1 != 8
, а количество несмежных чисел равно two
.
Все записи 0
проверяются, и алгоритм будет рассматривать следующее число, которое есть 2
, но, как вы видите выше, в массиве есть только одна запись числа, 2
которая есть [2, 1]
, и из-за этого будет рассмотрен следующий номер, то же самое произойдет для всех чисел, поэтому давайте напрямую посмотрим на число 4
, и оно имеет более одной записи в качествепоказано ниже,
[ 4
, 5], [ 4
, 3]
затем отсортируйте эти записи по индексу,
[ 4
, 3], [ 4
, 5]
здесь снова индексы не являются смежными индексами 3 1 != 5
, а количество не смежных чисел равно two
. Тот же процесс будет применен ко всем числам, и окончательный ответ будет максимальным не смежным числом count = 2
Для другого примера массива [4, 4, 4, 4, 4]
конечное число и индексный массив этого будут,
[ 4
, 0], [ 4
, 1], [ 4
, 2], [ 4
, 3], [ 4
, 4]
И, как вы можете видеть, индекс 0
, 2
, 4
не являются смежными индексами и максимальным несмежным числом count = 3
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
std::size_t countNonAdjacentEntries(std::vector<std::pair<int, std::size_t>>::const_iterator firstIt,
std::vector<std::pair<int, std::size_t>>::const_iterator lastIt){
std::size_t count = 0;
for(std::vector<std::pair<int, std::size_t>>::const_iterator preIt = firstIt, it = preIt 1; lastIt != it;){
if(preIt->second 1 != it->second){
count;
preIt = it;
it;
}
else{
it;
}
}
count;
return count;
}
std::size_t maxNonAdjacentNumber(const std::vector<int>amp; numbers){
std::vector<std::pair<int, std::size_t>> numAndIndex;
numAndIndex.reserve(numbers.size());
for(std::vector<int>::size_type i = 0, numbersCount = numbers.size(); i < numbersCount; i){
numAndIndex.emplace_back(numbers[i], i);
}
std::sort(numAndIndex.begin(), numAndIndex.end(),
[](const std::pair<int, std::size_t>amp; a, const std::pair<int, std::size_t>amp; b){
return a.first < b.first;});
std::size_t count = 0;
for(std::vector<std::pair<int, std::size_t>>::const_iterator it = numAndIndex.cbegin(), endIt = numAndIndex.cend();
endIt != it; ){
std::vector<std::pair<int, std::size_t>>::const_iterator upBoundIt = std::upper_bound( it 1, endIt, it->first,
[](int val, const std::pair<int, std::size_t>amp; ele){return val < ele.first;});
if(upBoundIt - it > 1){
std::sort(numAndIndex.begin(), numAndIndex.end(),
[](const std::pair<int, std::size_t>amp; a, const std::pair<int, std::size_t>amp; b){
return a.second < b.second;});
count = std::max(count, countNonAdjacentEntries(it, upBoundIt));
it = upBoundIt;
}
else{
it;
}
}
return count;
}
int main(){
cout<< "[9, 2, 3, 4, 0, 4, 5, 6, 0, 8] => "<< maxNonAdjacentNumber({9, 2, 3, 4, 0, 4, 5, 6, 0, 8})<< 'n';
cout<< "[4, 4, 4, 4, 4] => "<< maxNonAdjacentNumber({4, 4, 4, 4, 4})<< 'n';
}
Вывод
[9, 2, 3, 4, 0, 4, 5, 6, 0, 8] => 2
[4, 4, 4, 4, 4] => 3
Ответ №3:
уникальный, чтобы удалить дубликаты, отсортировать оставшиеся скопления, затем найти самый длинный прогон.
template<class T, class A>
std::optional<T> most_runs_of( std::vector<T, A> r ) {
if (r.empty()) return std::nullopt;
r.erase( std::unique( begin(r), end(r) ), end(r) );
std::sort( begin(r), end(r) );
T winner = r.front();
std::size_t winner_count = 0;
T const* cur = nullptr;
std::size_t cur_count = 0;
for (T constamp; e:r) {
if (e == winner)
{
winner_count;
continue;
}
if (cur amp;amp; *cur==e) {
cur_count;
if (cur_count > winner_count) {
winner = e;
winner_count = cur_count;
cur = nullptr;
continue;
}
}
cur = std::addressof(e);
cur_count = 1;
}
return winner;
}
Это копирует std::vector
и делает это на месте в копии в O (nlgn) и O (n) пространстве.
Если вам не нужно std::vector
после того, как вы вызовете вышеуказанное, std::move
включите его в алгоритм.
Комментарии:
1. А как насчет смежной части?
2.
Eliminates all except the first element from every consecutive group
таким образом, 2-й пример OP [4,4,4,4,4] будет уменьшен до [4]?