【问题标题】:Finding largest sorted selection寻找最大的排序选择
【发布时间】:2018-12-16 06:08:34
【问题描述】:

示例:给定 [1 2 3 10 7 8 9],我寻找给出 [1 1 1 0 1 1 1] 的算法。

我有一个未排序的数组作为输入。作为输出,我寻找最大的排序选择。

  • selection”是指一个长度相同的数组,包含 1 和 0(如果元素被选中)。
  • 使用 "sorted" 我的意思是选定的元素构成一个排序数组 - 在上面的示例中:[1 2 3 7 8 9]。
  • 最大的”是指没有排序的选择中包含更多的 1。

最坏的情况:我必须尝试所有 2^{0,1} 种可能的选择。有没有更快的算法来做到这一点?我不记得 CS 学习中的任何内容,也无法在网上找到任何内容(至少按照我的措辞)。

【问题讨论】:

标签: arrays algorithm dynamic-programming lis


【解决方案1】:

是的,这可以通过动态规划解决。

您必须创建另一个长度与给定数组相等的数组,让我们将其命名为 arr

arr[index] 将存储子数组的最大长度,如果从 givenArray[0...index] 和之后的元素 givenArray[index] 考虑数组,则 givenArray[index] 是排序顺序中的最后一个元素已添加。

从 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

【讨论】:

  • 不过,这太复杂了。
【解决方案2】:

在这里,我编写了一个方法 largestSortedSelection,它以元素向量作为输入(如 [1 2 3 10 7 8 9] )并返回布尔向量,其真/假代表 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 : 以排序递增的形式保存元素。

  • selection : 以 0/1 的形式保存答案
  • sortedList 中的lower_bound 函数:返回大于或等于的第一个元素。

如果您在理解源代码方面有困难,请告诉我。
因为我在一个循环中使用了 N 次 lower_bound 函数(其复杂度为 logN )。因此,整体时间复杂度为:O( N logN )
内存复杂度将是 O(N),因为我使用内存来保存 N 个元素。

【讨论】:

  • 对于输入 vector&lt;int&gt; v {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; 似乎只给出了 0 和 2 的错误结果?
  • 该算法返回:[1 0 0 0 1 0 1 0 0 1 0 0 0 1 0 1],表示{0,2,6,9,11,15}为选中的排序列表。
【解决方案3】:

感谢大家的帮助。这是我最终得到的 Wikipedia 伪代码的 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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    相关资源
    最近更新 更多