查找具有最大乘积的数组的两个元素

时间:2019-10-25 17:41:57

标签: c++ algorithm

我需要找到两个具有最大乘积的数组元素,然后输出它们的乘法。我试图对数组进行排序,然后搜索最大乘积,但是我的代码无法用于多个输入(我将在问题末尾给出),因为结果是0.00。我想我的if语句找不到要分配给'sand'的正确值,但是我不知道该如何写。 这是我正在使用的代码:

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <functional>
using namespace std;

int main() {
  int n;
  double a[10], sand=0; 
  cin >> n;

  for(int i = 0; i < n; i++)
  { 
    cin >> a[i];
  }
sort(a,a+n);
  for(int i = 0; i <n; i++)
  { for (int j=i+1;j<n;j++){
    if(a[i]*a[j]>i*j)
    {    sand=(a[i])*(a[j]);
  }
  }
  }

  cout<<fixed<<setprecision(2)<<sand;
}

这是输入:

2
5 -8

这是我应该得到的输出:

-40.00

我得到0.00代替。 第二个输入:

4
0 0.2 0.4 0.5

我应该得到的输出:

0.20

我的代码再次获得0.00作为输出。

3 个答案:

答案 0 :(得分:2)

对数组排序一次(假设n >= 2),结果是:

std::max(a[0] * a[1], a[n - 2] * a[n - 1]);

a[0] * a[1]处理“大”负数。
a[n - 2] * a[n - 1]处理一般情况:“大”正数。

您的第二个循环看起来像蛮力的,因此应该(不再需要std::sort):

auto sand = a[0] * a[1];
for (int i = 0; i < n; i++) {
    for (int j = i + 1; j < n; j++) {
        srand = std::max(srand, a[i] * a[j]);
    }
}

答案 1 :(得分:2)

您可以在O(n^2)的时间内找到答案,而不是使用两个for循环(复杂度O(nlog(n)))或使用排序(复杂度O(n)。而且,您甚至不需要数组来存储数字!

跟踪两个最低元素和两个最高元素。令变量为minAminBmaxAmaxB。数组中任何两个数字的最大乘积将为minA*minBmaxA*maxB

假设n >= 2

#include <iostream>
#include <limits>
#include <algorithm>

using namespace std;

constexpr double MIN = numeric_limits<double>::min();
constexpr double MAX = numeric_limits<double>::max();

int main()
{
    int n;
    cin >> n;

    double minA, minB, maxA, maxB;
    minA = minB = MAX;
    maxA = maxB = MIN;

    for (int i = 0; i < n; ++i)
    {
        double x;
        cin >> x;

        if (x > maxA)
        {
            maxB = maxA;
            maxA = x;
        }
        else if (x > maxB)
            maxB = x;

        if (x < minA)
        {
            minB = minA;
            minA = x;
        }
        else if (x < minB)
            minB = x;
    }

    cout << max(minA * minB, maxA * maxB) << endl;
}

答案 2 :(得分:1)

您可以使用四种潜在的算法,如下所示:

#include <algorithm>
#include <cassert>
#include <chrono>
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <vector>

//O(N^2): Compare all elements against each other and keep the biggest product
//We pass `data` by value so the order of the array as invariant between tests
template<class T>
T Method1(std::vector<T> &data){
  assert(data.size()>=2);
  T bestval=data[0]*data[1];
  for(int i=0;i<data.size();i++)
  for(int j=i+1;j<data.size();j++){
    const auto val = data[i]*data[j];
    if(val>bestval)
      bestval = val;
  }

  return bestval;
}

//O(N log N): Sort the elements and look at the largest potential products
//We pass `data` by value so the order of the array as invariant between tests
template<class T>
T Method2(std::vector<T> &data){
  assert(data.size()>=2);
  std::sort(data.begin(), data.end());

  return std::max(data[0]*data[1], data[data.size()-1]*data[data.size()-2]);
}

//O(N): Use Quickselect to look at the largest potential products
//We pass `data` by value so the order of the array as invariant between tests
template<class T>
T Method3(std::vector<T> &data){
  assert(data.size()>=2);
  std::nth_element(data.begin(),data.begin()+1,data.end());
  auto smallval = data[0]*data[1];
  std::nth_element(data.begin(),data.end()-2,data.end());
  auto bigval = (data[data.size()-2]*data[data.size()-1]);

  return std::max(smallval,bigval);
}

//O(N): Explicitly find the pairs with the largest potential products
//We pass `data` by value so the order of the array as invariant between tests
template<class T>
T Method4(std::vector<T> &data){
  assert(data.size()>=2);
  T small1 = std::numeric_limits<T>::max();
  T small2 = std::numeric_limits<T>::max();
  T large1 = std::numeric_limits<T>::min();
  T large2 = std::numeric_limits<T>::min();

  for(const auto &x: data){
    if(x<=small1){
      small2 = small1;
      small1 = x;
    } else if(x<=small2){
      small2 = x;
    }

    if(x>=large1){
      large2 = large1;
      large1 = x;
    } else if(x>=large2){
      large2 = x;
    }
  }

  return std::max(small1*small2,large1*large2);
}


template<class Func>
void TimeIt(std::string message, Func func){
  long x; //Dummy variable to prevent compiler optimizations
  const auto start = std::chrono::high_resolution_clock::now();
  const int TEST_COUNT=100;
  for(int i=0;i<TEST_COUNT;i++)
    x += func();
  const auto finish = std::chrono::high_resolution_clock::now();
  std::cout << message <<" time: " << std::fixed << ((std::chrono::duration<double>)(finish-start)).count()/TEST_COUNT << "s "<<std::endl;
}

int main(){
  const int N=100000;
  std::vector<long> data;      //Don't change this
  std::vector<long> data_orig; //Let the methods mutate this
  data.reserve(N);
  for(int i=0;i<N;i++){
    data.push_back(rand()%2000001-1000000); //Get a random number in the range [-1000000,1000000]
  }

  data_orig = data;

  std::cout<<"Method1 = "<<Method1(data)<<std::endl;
  std::cout<<"Method2 = "<<Method2(data)<<std::endl;
  std::cout<<"Method3 = "<<Method3(data)<<std::endl;
  std::cout<<"Method4 = "<<Method4(data)<<std::endl;

  //Do they all give the same answer?
  assert(Method1(data)==Method2(data));
  assert(Method2(data)==Method3(data));
  assert(Method3(data)==Method4(data));

  TimeIt("Method1", [&](){data=data_orig; return Method1(data);});
  TimeIt("Method2", [&](){data=data_orig; return Method2(data);});
  TimeIt("Method3", [&](){data=data_orig; return Method3(data);});
  TimeIt("Method4", [&](){data=data_orig; return Method4(data);});
}

在我的计算机上,所有这些都给出了相同的答案,这很好地证明了它们是正确的:

Method1 = 999976000143
Method2 = 999976000143
Method3 = 999976000143
Method4 = 999976000143

计时结果符合我们的预期,平均得到了100次迭代:

Method1 time: 2.624980s 
Method2 time: 0.004581s 
Method3 time: 0.000806s 
Method4 time: 0.000118s