【问题标题】:How to find the a triplet in an array of numbers having maximum product?如何在具有最大乘积的数字数组中找到三元组?
【发布时间】:2017-03-06 17:41:25
【问题描述】:

今天我被以下问题卡住了。请提供一些线索,声明如下:

给定一个大小为n 的数组A[]。在以下约束条件下最大化A[i]*A[j]*A[k]

  • i
  • A[i]

我尝试的代码如下:

#include<iostream>
using namespace std;

int main(){
  int A[]={1,3,6,8,9};
  int max=0;
  int n=sizeof(A)/sizeof(A[0]);
  for(int i=0;i<n;i++)
      for(int j=i+1;j<n;j++)
        for(int k=j+1;k<n;k++)
        {
          if(A[i]<A[j]&&A[j]<A[k]&&max<A[i]*A[j]*A[k])
            max=A[i]*A[j]*A[k];
        }
        cout<<max;
   return 0;
}

【问题讨论】:

  • 你是不是不小心发帖了?
  • 你现在做了什么?
  • 不,但我是这个网站的新手,所以如果我犯了错误,很抱歉。
  • 我已经找到了 O(n^3) 的解决方案,但效率不高。你能建议其他技术吗..
  • 请提供您尝试的解决方案的代码

标签: algorithm complexity-theory maximize


【解决方案1】:

有一个简单的 O(N^2) 算法。这是大纲:

  1. 对于每个元素y
  2. 搜索小于yy之前的最大元素x
  3. 搜索大于yy 之后的最大元素z

第一步是O(N),第二步和第三步可以在同一个循环中完成,O(N),总共是O(N^2)


也有O(N lg N)的算法,不过比较复杂:

我们可以在 O(N) 中预先计算并在 O(1) 中查询以找到范围 [l,r] 中的最大值。 (最初的想法是使用段树或任何 RMQ 结构,感谢@PetarPetrovic 指出)

此外,我们在遍历数组中的每个元素时动态构建一个集合(排序列表)。伪代码如下:

Array A = []
Set S = {}
Ans = 0

For i = 0 to N // O(N)
  // A[i] is y
  x = binary search S, maximum element in S which is < A[i] //O(lg N)
  z = RMQ(i+1, N) // O(lg N), or O(1) if we precompute in O(N)
  if(x < A[i] && A[i] < z) Ans = Max(Ans, x*A[i]*z)
  Insert A[i] into S // O(lg N)
//Total is O(N lg N)      

我们尝试将A[i] 视为中间元素y

由于我们有一个包含i 之前的所有元素的有序集合,我们可以使用该集合对最大有效x 进行二分搜索。之后我们将当前元素插入到这个集合中。

我们使用 O(N) 来预先计算一个数组并在 O(1) 中查询以找到范围 [i+1, N-1] 中的最大值。找到的号码是z

如果(x,y,z) 是有效元组并且大于当前答案,我们会更新答案。

【讨论】:

  • 如果只想在 [i + 1, N - 1] 范围内找到最大值,我认为可以在 O(n) prepossess 和 O(1) 查询时间内完成
  • @PetarPetrovic 是的,你是对的,仔细想想,它仍然是 O(N lg N) :)
  • @shole 感谢您提出如此有效的解决方案,这是面试官作为提示指出的确切方法,但当时我无法理解坏运气......
【解决方案2】:

给定 i

for(i = 0; i < n; ++i) {
    for(j = i + 1; j < n; ++j){
         if (A[i] < A[j]) {
             for(k = j + 1; k < n; ++k){
                 if(A[j] < A[k]) {
                 /*DoSomething with i,j,k*/
                 }
            }
         }
    }
}

这主要是缩进的噩梦。

【讨论】:

  • 一个约束是A[i] &lt; A[j],所以你可以做for ( j = i + 1 ; j &lt; n ; ++j ) if ( A[i] &lt; A[j] ) for ( k = j + 1 ; k &lt; n ; ++k ) { /* do something */ }
  • @max66 这个解决方案的时间复杂度是 O(n^3) 对。如果是,那么这不是有效的。面试官要求做得更好。
  • @max66 已更新,谢谢。在最坏的情况下(i = 0,j = 0,k = 0),这只是 O(n^3),在其他情况下它会比这更快。
  • @AlexG yes ur rt 但是我们可以用 O(nlogn) 或 O(n^2) 之类的方法来做到这一点吗?
  • @Rahul - 是的:根据我的建议,保持 O(n^3)。
【解决方案3】:

下面的解应该是O(n^2)

#include <stack>
#include <iostream>
#include <stdexcept>

template <typename T>
std::stack<T> getStack (T const * a, std::size_t dimA)
 {
   if ( nullptr == a )
      throw std::runtime_error("nullptr in getStack()");

   if ( 0U == dimA )
      throw std::runtime_error("no values in getStack()");

   T              top;
   std::stack<T>  s;
   std::size_t    pos{ 0U };

   s.push(top = a[pos]);

   do
    {
      if ( top < a[pos] )
         s.push(top = a[pos]);
    }
   while ( ++pos < dimA );

   return s;
 }


int main()
 {
   int          a[] { 34, 12, 3, 7, 29, 45 };
   std::size_t  dimA { sizeof(a)/sizeof(a[0]) };
   std::size_t  numMult { 3U };


   std::stack<int> s;

   std::size_t     pos { 0U };

   do
    {
      s = getStack(a+pos, dimA - pos);
    }
   while ( (s.size() < numMult) && (numMult <= (dimA - ++pos)) );

   if ( s.size() < numMult )
      std::cout << "there is no solution" << std::endl;
   else
    {
      int res { s.top() };

      for ( auto ui = 1U ; ui < numMult ; ++ui )
       {
         s.pop();

         res *= s.top(); 
       }

      std::cout << "the solution is " << res << std::endl;
    }

   return 0;
 }

【讨论】:

  • 这个方法看起来挺有意思的。
猜你喜欢
  • 2019-10-24
  • 1970-01-01
  • 2017-01-08
  • 2013-12-31
  • 2020-08-30
  • 2020-09-06
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
相关资源
最近更新 更多