【问题标题】:Finding K combination of three items with minimum product求三项最小乘积的 K 个组合
【发布时间】:2023-03-09 13:18:01
【问题描述】:

在解决一个问题时,我遇到了一种情况,我必须从给定的正数数组中找到三个项目组合的前 k 个产品,这样产品应该是最小的。 给定数组A,大小为n,高效地找到数组中三个不同项的最小乘积k。让我们称之为MP 这样

MP[i] = A[j]* A[l]*A[m] 

i<K, j!=l!=mk<n在哪里

我当时尝试的是获取所有可能的产品,然后对它们进行排序以获得前 k 个产品。但我知道这不是有效的,因为首先 O(N^3) 用于查找所有组合产品,然后至少 O(NlogN) 用于排序 N^3 组合。所以在我的情况下,数组大小并不大,但我想知道如何更有效地解决同样的问题。

【问题讨论】:

  • 数组可以包含负数吗??
  • 数组只包含正数。

标签: arrays algorithm math combinations


【解决方案1】:

其他解决方案的问题在于他们的贪婪选择不是最优的。

一个简单的基于优先队列的解决方案将为这个问题提供最佳解决方案。 min_product 是传递所需数组的函数,映射用于跟踪已经看到的元组。我使用了一个简单的 stl 优先级队列。

//// Asume the vector a(size>=3) is sorted    
std::vector<int> a;
struct triplet{
    int i,j,k;
};

long long value(triplet& p1){
    return (long long)a[p1.i]*(long long)a[p1.j]*a[p1.k];
}

struct CompareTriplet {
    bool operator()(triplet const & p1, triplet const & p2) {
        return value(p1) > value(p2);
    }
};

void push_heap(std::priority_queue<triplet, std::vector<triplet> pq, CompareTriplet>& pq,triplet &t,std::vector<triplet>& m;){
    if (m.find(t)!=m.end()){
        m[t]=1;
        pq.push(t);
    }
}

std::vector<long long> min_product(int k){

    sort(a.begin(), a.end()); // sort if not sorted.
    int n=a.size();

    std::unodered_map<triplet,bool> m;
    std::vector<long long> MP(k);

    std::priority_queue<triplet, std::vector<triplet>, CompareTriplet> pq;

    push_heap(pq,triplet{0,1,2},m);

    for(int i=0; !pq.empty() and i<k;i++){
        auto tp = pq.top(); pq.pop();
        MP[i]=value(tp);

        if (tp.i+1<tp.j){
            push_heap(pq,triplet{tp.i+1,tp.j,tp.k},m);
        }
        if (tp.j+1<tp.k){
            push_heap(pq,triplet{tp.i,tp.j+1,tp.k},m);
        }
        if (tp.k+1<n){
            push_heap(pq,triplet{tp.i,tp.j,tp.k+1},m);
        }
    }
    return MP
}

复杂性

如果数组没有排序,那么让它排序是这里的瓶颈。实际上在任何时候,我们都需要 top i (

对于已排序的给定数组。

因为堆中最多可以有 2*k 个元素,并且为了获取 MP 的每个元素,需要进行 O(k) 次操作(堆和映射)。因此,运行时间复杂度为 O( k*log(k) )

是的,它独立于 n。

【讨论】:

  • 这是我在回答中建议的算法的一种变体,因为它尊重不需要贪婪的选择。不幸的是,它假定 A 已排序,这不是问题中的要求。排序增加了O(n log(n)) 的复杂性,并且在A 未排序时远非最佳。解决方案不需要对A 进行排序(请参阅我的回答)。
  • @NicolaiEhemann,在我的算法中,我实际上并不需要在一开始就对 a 的元素进行排序。我将从数组创建另一个堆,然后删除 min 并在实际需要时使用它 [ith remove_top 将在 k==i 时调用] 。这样我的复杂性仍然是 k 的函数。我将为此更新代码。
  • 好吧,如果输入数组之前没有排序,你肯定至少要查看A的每个元素才能找到最小的,所以复杂度必须是n的函数。如果A之前排序,复杂度只取决于k,我的算法比你的差。
  • 哦,我明白了它的复杂性,无论如何都取决于 n。
  • 事实证明,我的解决方案完全错误。如果能以正确的复杂性对您的描述进行更正式的描述,那就太好了。
猜你喜欢
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2017-12-04
  • 2019-10-24
  • 1970-01-01
  • 2014-01-31
  • 2021-09-23
  • 2022-11-19
相关资源
最近更新 更多