Нахождение самого большого отсортированного выбора

Пример: учитывая [1 2 3 10 7 8 9], я ищу алгоритм, дающий [1 1 1 0 1 1 1].

У меня есть несортированный массив в качестве ввода. В качестве вывода я ищу самый большой отсортированный выбор.

  • Под "выделением" я подразумеваю массив одинаковой длины, содержащий 1 с и 0 с (если элементы выбраны или нет).
  • Под "отсортированным" я подразумеваю, что выбранные элементы составляют отсортированный массив - в приведенном выше примере: [1 2 3 7 8 9].
  • И под "самым большим" я подразумеваю, что нет отсортированного выбора, который имеет больше 1 в нем.

В худшем случае: я должен попробовать все 2^{0,1} возможных выборов. Есть ли более быстрый алгоритм для этого? Я не помню ни одного из исследования CS и не мог найти ничего онлайн (по крайней мере, с моей формулировкой).

3 ответа

Да, это можно решить с помощью динамического программирования.

Вы должны создать еще один массив пары длины, равной данному массиву, назовем его arr

arr [index] будет хранить максимальную длину подмассива, так что данный Array[индекс] является последним элементом в отсортированном порядке, если массив рассматривается из данного массива [0... индекс] и элемента, после которого добавляется данный массив [индекс].

Из arr вы можете найти максимальную длину отсортированного массива и создать массив.

for (int i = 0;i<givenArray.size(); i++) {

    int after = -1;
    int length = 0;
    for(int j = 0;j<i;j++) {
        if (givenArray[j] < givenArray[i] && length < arr[j].maxLengthTillNow) {
            length = arr[j].maxLengthTillNow;
            after = j;
        }
    }

    arr[i].maxLengthTillNow = length + 1;
    arr[i].after = j;
}

сложность: n*n

Здесь я написал метод largeSortedSelection, который принимает вектор элементов в качестве входных данных (например, как [1 2 3 10 7 8 9]) и возвращает логический вектор с true/false, представляющим 1/0, указывающий выбор индекса в ответе или нет (например, как [1 1 1 0 1 1 1]).

vector< bool >largestSortedSelection( vector<int>&v ){
int n = v.size(); 
vector< int >selectedLen(n);
vector< int >sortedList;
int maxLen = 1;
for(int i = 0; i<n; ++i){
    int lb = lower_bound(sortedList.begin(),sortedList.end(),v[i])-sortedList.begin();
    if( lb!=(int)sortedList.size() ){
        selectedLen[i]=lb+1;
        sortedList[lb]=v[i];
    }
    else {
        sortedList.push_back(v[i]);
        selectedLen[i]=(int)sortedList.size();
    }
    maxLen =  max( maxLen, selectedLen[i] );
}
int lst = INT_MAX;//assuming maximum element will be less than INT_MAX
int len = maxLen+1;
vector< bool >selection(n,0);
for(int i = n-1; i>=0; --i ){
    if( v[i]<lst && selectedLen[i]+1 == len ){
        selection[i] = 1;
        lst = v[i];
        len--;
    }
  }
  return selection;
}

В этом методе:

  • selectedLen (i): наибольшая длина отсортированного списка, заканчивающаяся индексом-i.

  • sortedList: содержит элементы в отсортированной возрастающей форме.

  • Выбор: содержит ответ в виде 0/1
  • Функция lower_bound в sortedList: возвращает первый элемент, который больше или равен.

Дайте мне знать, если вы чувствуете трудности в понимании исходного кода.
Как я использовал функцию lower_bound (которая имеет сложность logN) N раз в цикле. Итак, общая сложность времени: O (N logN).
Сложность памяти будет O(N), так как я использую память для хранения N элементов.

Спасибо всем за помощь. Это реализация C++ псевдокода Википедии, с которой я закончил:

/// Return indice of the a longest increasing subsequence.
/// implementation of https://en.wikipedia.org/wiki/Longest_increasing_subsequence
template<class T>
std::vector<size_t> indiceOfLongesIncreasingSubsequence(const std::vector<T>& v)
{
  std::vector<size_t> P(v.size()), M(v.size() + 1);
  size_t L = 0;
  for(size_t i = 0; i < v.size(); ++i)
  {
    // binary search for the largest positive j <= L such that v[M[j]] < v[i]
    size_t lo = 1, hi = L;
    while(lo <= hi)
    {
      size_t mid = (lo + hi)/2;
      if(v[M[mid]] < v[i])
        lo = mid+1;
      else
        hi = mid-1;
    }

    // predecessor of v[i] is the last index of the subsequence of length lo-1
    P[i] = M[lo-1];
    M[lo] = i;

    if(lo > L)
      L = lo;
  }

  // reconstruct the longest increasing subsequence
  std::vector<size_t> ind(L);
  size_t k = M[L];
  for(size_t i = 0; i < L; ++i)
  {
    ind[L-1-i] = k;
    k = P[k];
  }

  return ind;
}

Чтобы получить вектор истинности / ложности, нужно:

vector<bool> selection(ind.size(), false);
for(size_t i: ind)
  selection[i] = true;
Другие вопросы по тегам