Arrays 查找数组中唯一对的第k个最小和

Arrays 查找数组中唯一对的第k个最小和,arrays,algorithm,sorting,Arrays,Algorithm,Sorting,给定一个数字数组,每个数字代表问题的难度。排队的人应该选择任意两个问题来解决。选择的两个问题应该是不同的,这对问题不应该由以前的任何人选择。因为他们知道困难,他们会选择困难之和最小的一对 找出站在队列第k个位置的人员的最小困难总和。i、 数组中唯一对的第k个最小和 方法1:蛮力方法(O(n2))计算所有可能的唯一和并将其存储在数组中,然后对唯一和数组进行排序以获得第k个元素 方法2:对数组排序并选择最小元素(对于前4个元素,我们可以有6个唯一对。因此,如果k小于或等于6,我们可以使用排序数组中的

给定一个数字数组,每个数字代表问题的难度。排队的人应该选择任意两个问题来解决。选择的两个问题应该是不同的,这对问题不应该由以前的任何人选择。因为他们知道困难,他们会选择困难之和最小的一对

找出站在队列第k个位置的人员的最小困难总和。i、 数组中唯一对的第k个最小和

方法1:蛮力方法(O(n2))计算所有可能的唯一和并将其存储在数组中,然后对唯一和数组进行排序以获得第k个元素

方法2:对数组排序并选择最小元素(对于前4个元素,我们可以有6个唯一对。因此,如果k小于或等于6,我们可以使用排序数组中的前4个元素来找到最小和),并对最小数组执行方法1

这两种方法没有解决超时情况。需要提高时间效率的解决方案

注意:不同的问题也可以有相同的难度(即数组可以包含重复的数字),默认情况下不按顺序排序

difficulties = [1,4,3,2,4]

Person comes first chooses: 1+2 = 3
2nd person: 1+3 = 4
3rd person: 1+4 (or) 1+4(since difficulty of two problems are 4) (or) 2+3 = 5
4th person: 2+3 (or) 1+4(based on the previous selection) = 5
最终需要的答案只是最小的和,而不是实际的元素

假设约束为:

2假设
k1
。所以,每次你减少一半的搜索空间。所以,总的时间复杂度将是
O(N*logN*logMaxsum)
,这对于
N来说是很清楚的。如果我们有一个由5个元素组成的数组,比如说
abcde
,那么要选择的对是
A+B、A+C、A+D、A+E、B+C、B+D、B+E、C+D、C+E和D+E
。所以我们最多可以有10个人排队。是这样吗?是的。唯一对的总数。i、 e.n(n-1)/2对用尝试过的方法和一个例子更新了问题。你能给我一些问题链接,这样我可以在这里回答之前尝试提交吗?另外,对于示例中的输入数组
困难=[1,4,3,2,4]
和语句“这两个问题应该不同”,意味着我无法生成两对
(1+4)
(1+4)
?您使用它们的实际元素或索引将它们视为不同的?@user3386109 K可以而且很可能会大于此值。由于迭代是基于maxSum的,因此这看起来仍然更耗时。困难[i]可能高达109,maxSum将是两个这样的元素的总和,其中数组的长度相对较小。@Manojkumar二进制搜索最多需要30次迭代。每一个都涉及10^5个元素的扫描。所以你最多需要几百万次手术。相比之下,
k
可以达到数十亿。这可能看起来很耗时,但事实并非如此。@Manojkumar有一个日志记录了元素的最大总和。即使困难[i]会达到1018,那么日志(1018)也是atmost 64。@Manojkumar此解决方案的规定复杂性是
N*logN*logS
,其中N是数组中的元素数,S是2个元素的最大和。因此,给定N=1e5和S=2e9,操作数估计为
1e5*17*31=53e6
。如果目标是在一秒钟内解决问题,那么这是一个相当合理的数字。@risingStark如果二进制搜索到数组的最后一部分,那么计算对数操作可以接近n^2,对吗?你能解释一下这部分吗
sort(difficulties)
low = difficulties[0] + difficulties[1] // Minimum possible sum
high = difficulties[n-1] + difficulties[n-2] // Maximum possible sum

while(high - low > 1){
    mid = low + (high - low)/2
    count = all pairs (i, j) and i < j such that difficulties[i] + difficulties[j] <= mid.
    if(count < k){
        low = mid +1 
    }else{
        high = mid
    }
}
Iteration 1:
low = 3
high = 8
mid = 5
count = 5 [(1 + 2), (1 + 3), (1 + 4), (1 + 4), (2 + 3)]
count < k, so low = mid + 1 = 6

----------

Iteration 2:
low = 6
high = 8
mid = 7
count = 9 [(1 + 2), (1 + 3), (1 + 4), (1 + 4), (2 + 3), (2 + 4), (2 + 4), (3 + 4), (3 + 4)]
count >= k, so high= mid = 7
#include<bits/stdc++.h>
#define ll long long int

using namespace std;

void solve();
int main(){
    solve();
    return 0;
}

map<int, int> m;
vector<ll> difficulties;
ll countFunction(ll sum){
    /*
    Function to count all the pairs of indices (i, j) such that
    i < j and  (difficulties[i] + difficulties[j]) <= sum
    */
    ll count = 0;

    int n = (int)difficulties.size();
    for(int i=0;i<n-1;i++){
        /*
        Here the outer for loop means that if I choose difficulties[i]
        as the first element of the pair, then the remaining sum is
        m - difficulties[i], so we just need to find the upper_bound of this value
        to find the count of all pairs with sum <= m.
        upper_bound is an in-built function in C++ STL.
        */
        int x= upper_bound(difficulties.begin(), difficulties.end(), sum-difficulties[i]) - (difficulties.begin() + i + 1);
        if(x<=0){
            /*
            We break here because the condition of i < j is violated
            and it will be violated for remaining values of i as well.
            */
            break;
        }
        //cout<<"x = "<<x<<endl;
        count += x;
    }
    return count;
}


bool isPossible(ll sum){
    /*
    Hashing based solution to check if atleast 1 pair with
    a particular exists in the difficultiesay.
    */
    int n = (int) difficulties.size();
    for(int i=0;i<n;i++){
        /*
        Choosing the ith element as first element of pair
        and checking if there exists an element with value = sum - difficulties[i]
        */
        if(difficulties[i] == (sum - difficulties[i])){
            // If the elements are equal then the frequency must be > 1
            if(m[difficulties[i]] > 1){
                return true;
            }
        }else{
            if(m[sum - difficulties[i]] > 0){
                return true;
            }
        }
    }
    return false;
}

void solve(){
    ll i, j, n, k;
    cin>>n>>k;
    difficulties.resize(n);
    m.clear(); // to run multiple test-cases
    for(i=0;i<n;i++){
        cin>>difficulties[i];
        m[difficulties[i]]++;
    }
    sort(difficulties.begin(), difficulties.end());


    // Using binary search on the possible values of sum.
    ll low = difficulties[0] + difficulties[1]; // Lowest possible sum after sorting
    ll high = difficulties[n-1] + difficulties[n-2]; // Highest possible sum after sorting
    while((high-low)>1){
        ll mid = low + (high - low)/2;
        ll count = countFunction(mid);
        //cout<<"Low = "<<low<<" high = "<<high<<" mid = "<<mid<<" count = "<<count<<endl;
        if (k > count){
            low = mid + 1;
        }else{
            high = mid;
        }
    }

    /*
    Now the answer can be low or high and we need to check
    if low or high is a possible sum and does it satisfy the constraints of k.

    For low to be the answer, we need to count the number of pairs with sum <=low.
    If this count is >=k, then low is the answer.
    But we also need to check whether low is a feasible sum.
    */
    if(isPossible(low) && countFunction(low)>=k){
        cout<<low<<endl;
    }else{
        cout<<high<<endl;
    }
}