需要更有效的方法来读取子数组

时间:2018-06-18 12:36:40

标签: arrays algorithm loops coding-efficiency time-limiting

问题陈述询问这些子阵列的数量,其中i <1。 j&lt; k,任何两个数字之和应大于或等于子数组中的第三个:

我做了什么:

我从i = 0到n-2跑了一个循环:   我使用的基本逻辑是,如果排序子阵列中的前两个元素大于或等于最大值,那么所有对都将大于任何元素。每次我得到子数组时,我都会在其中添加下一个元素并再次设置这三个变量。我正在通过15/20 TC,其他人正在接受TLE:
约束:
1·; = N&LT = 10 ^ 5
1·= AI&LT = 10 ^ 9

for(int i=0;i<n-2;i++)
{
    int r=i+2;
    vector<int> temp(inp.begin()+i,inp.begin()+r+1);
    sort(temp.begin(),temp.end());
    max_elem=temp[1];min_elem=temp[0];
    int maximum=temp[temp.size()-1];


    //cout<<max_elem<<" "<<min_elem<<"\n";

    while(r<n && max_elem+min_elem >= maximum)
    {   
        //cout<<max_elem<<" "<<min_elem<<" "<<inp[r]<<"\n";
        cnt++;
        r++;

        if(inp[r]<min_elem) {max_elem=min_elem;min_elem=inp[r];}
        else if(inp[r]<max_elem) max_elem=inp[r];
        else if(inp[r]>maximum) maximum=inp[r];

    }

}
cout<<cnt<<"\n";

示例TC:

I1
5
7 6 5 3 4
O1
6
说明:
6个子阵列满足条件:(7,6,5),(7,6,5,3),(7,6,5,3,4),(6,5,3) ,(6,5,3,4),(5,3,4)。

I2
5
1 2 3 5 6
O2
3
说明:
(1,2,3),(2,3,5),(3,5,6) - (注:1,2,3,5不是ans coz 1 + 2&lt; 5)

2 个答案:

答案 0 :(得分:0)

这样做的一种天真的方法是如下。你的逻辑是正确的,这是我实现的。我用单次传递(N)改变了排序(NlogN),只找到了2个最小和最大的数字。我没有编译代码,也不确定它是否按预期工作。它具有(N * N * N)的总体复杂度。

执行一些额外的检查可以提高执行时间:

    可以在每个内部(k)循环之后检查
  • min1 + min2 >= max条件,如果违反单个案例则会中断。
  • 如果对于子阵列4-7不满足条件,则不需要检查包括4-7的任何其他子串。通过在每个循环之前存储违规案例并对其进行检查,可以提高整体执行时间。

    int min1;
    int min2;
    int max;
    int count = 0;
    for(int i = 2; i < n; i++){
        for(int j = 0; j < i - 2; j++){
            max = -1;
            min1 = min2 = 1000000000;
            for(int k = j; k <= i; k++){
                if(inp[k] > max)
                    max = inp[k];
                if(inp[k] < min1){
                    min1 = inp[k];
                    continue;
                }
                if(inp[k] < min2){
                    min2 = inp[k];
                }
            }
            if(min1 + min2 >= max)
                count++;
        }
    } 
    

答案 1 :(得分:0)

可能存在一些错误,但这是O(n log n)解决方案的一般想法:

我们保留了一个从startIdx到endIdx的元素窗口。如果它是一个有效的子数组,这意味着我们可以扩展它,我们可以添加另一个元素,所以我们增加endIdx。如果它无效,无论我们扩展它多少都不会有效,所以我们需要通过增加startIdx来减少它。

伪代码:

multiset<int> nums;

int startIdx = 0, endIdx = 0;
int sol = 0;

while(endIdx != inp.size()) {
    if (endIdx - startIdx < 3) {
       nums.add(inp[endIdx]);  
       endIdx++;
    } else  {
       if (nums.lowestElement() + nums.secondLowestElement() < nums.highestElement()) {
          nums.remove(nums.find(inp[startIdx]));
          startIdx++;
       } else { 
            sol += endIdx - startIdx - 2; // amount of valid subarrays ending in inp[endIdx - 1]
            nums.add(inp[endIdx]);  
            endIdx++;
       }
    }
}