【问题标题】:Smallest Lexicographic Subsequence of size k in an Array数组中大小为 k 的最小词典子序列
【发布时间】:2016-06-13 08:17:03
【问题描述】:

给定一个整数数组,找到大小为 k 的最小词法子序列。 EX: Array : [3,1,5,3,5,9,2] k =4 Expected Soultion : 1 3 5 2

【问题讨论】:

标签: arrays dynamic-programming greedy


【解决方案1】:
  1. 我建议您可以尝试使用修改后的归并排序。的地方
  2. 修改为合并部分,丢弃重复值。
  3. 选择最小的四个

复杂度是o(n logn) 还在思考复杂度能不能是o(n)

【讨论】:

  • 这个解决方案永远不会奏效。选择最小的四个不是本意。选择字典最小的序列是目的。例如:对于输入2 1 1 1 9 9 9,选择1 9 9 9 优于2 1 1 1
【解决方案2】:

这是一个应该可以工作的greedy 算法:

Choose Next Number ( lastChoosenIndex, k ) {

    minNum = Find out what is the smallest number from lastChoosenIndex to ArraySize-k

    //Now we know this number is the best possible candidate to be the next number.
    lastChoosenIndex = earliest possible occurance of minNum after lastChoosenIndex

    //do the same process for k-1
    Choose Next Number ( lastChoosenIndex, k-1 )
}

上面的算法复杂度很高。

但是我们可以pre-sort 所有数组元素paired 和它们的array index 并使用单个循环贪婪地执行相同的过程。 由于我们使用排序复杂度仍然是n*log(n)

【讨论】:

  • 这是有道理的,但是这个解决方案没有动态编程方法吗?
  • 看这里预期的序列大小k 是固定的。你想要最小的那个大小的 lex。我认为任何动态编程方法都非常复杂,并且基本上最终都会做贪婪方法所做的事情。
【解决方案3】:

如果我正确理解了这个问题,这里有一个 DP 算法应该可以工作,但它需要 O(NK) time

//k is the given size and n is the size of the array
create an array dp[k+1][n+1]

initialize the first column with the maximum integer value (we'll need it later)
and the first row with 0's (keep element dp[0][0] = 0)

now run the loop while building the solution 

for(int i=1; i<=k; i++) {
  for(int j=1; j<=n; j++) {
      //if the number of elements in the array is less than the size required (K) 
      //initialize it with the maximum integer value
      if( j < i ) {
          dp[i][j] = MAX_INT_VALUE;
      }else {
          //last minimum of size k-1 with present element or last minimum of size k
          dp[i][j] = minimun (dp[i-1][j-1] + arr[j-1], dp[i][j-1]);
      } 
   }
}
//it consists the solution
return dp[k][n];

数组的最后一个元素包含解。

【讨论】:

    【解决方案4】:

    这个问题可以通过维护一个双端队列(deque)在 O(n) 内解决。我们从左到右迭代元素,并确保双端队列始终保持到该点的最小字典序列。仅当当前元素小于 deque 中的元素并且 deque 中的总元素加上剩余要处理的元素至少为 k 时,我们才应该弹出元素。

    vector<int> smallestLexo(vector<int> s, int k) {
        deque<int> dq;
        for(int i = 0; i < s.size(); i++) {
            while(!dq.empty() && s[i] < dq.back() && (dq.size() + (s.size() - i - 1)) >= k) {
                dq.pop_back();
            }
            dq.push_back(s[i]);
        }
        return vector<int> (dq.begin(), dq.end());
    }
    

    【讨论】:

      【解决方案5】:

      Ankit Joshi 的回答很有效。但我认为它可以只用一个向量本身来完成,而不是使用一个双端队列,因为所有完成的操作都可以在向量中使用。同样在 Ankit Joshi 的回答中,双端队列可以包含额外的元素,我们必须在返回之前手动弹出这些元素。在返回之前添加这些行。

      while(dq.size() > k)
      {
             dq.pop_back();
      }
      

      【讨论】:

        【解决方案6】:

        可以使用 RMQ 在 O(n) + Klog(n) 中完成。 在 O(n) 中构造一个 RMQ。 现在找到每个 ith 元素将是最小的序列。从 pos [x(i-1)+1 到 n-(Ki)] (对于 i [1 to K] ,其中 x0 = 0, xi 是给定数组中第 ith 个最小元素的位置)

        【讨论】:

          猜你喜欢
          • 2022-12-20
          • 1970-01-01
          • 2021-04-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-15
          • 1970-01-01
          相关资源
          最近更新 更多