找下标最大的差值

在给定数组A中,找到满足A[p]>=A[q]条件的p-q的最大值,要求时间复杂度和空间复杂度均为O(n)。一种方法是构建递减数组b,通过遍历A找到最小的j使得A[i]>b[j];另一种方法利用栈,逆序遍历A,当a[j]>=a[s.top()]时更新最大差值ans,并在不满足条件时弹出栈顶元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

question:

给定一个数组A,找出A[p]>=A[q] 中 p-q的最大值。

要求O(n)的时间和空间复杂度

answer1:

计算数组b,使得b[j]为A[j...n-1]的最大值。那数组就是一个递减的数组。
遍历A数组,当A[i]<b[j]时,说明在j...n-1之间有k使得A[j]<A[k]。那找到最小的j使得A[i]>b[j],这样找到如果q为i时的最大差值为j-i-1。

这样仍旧为双层循环不满足空间复杂度。

这里我们发现,如果i1和j1满足条件时,即差值为j1-i1-1。这时如果i再增加,j如果减少也不再满足j-i-1>j1-i1-1.
所以j是没有必要减小的。
这样的复杂度就可以变现成O(n)

#include<iostream>
using namespace std;

int main(){
    int n;
    int a[1000],b[1000];
    cin>>n;
    for(int i = 0;i<n;i++)cin>>a[i];
    for(int j = n-1;j>=0;j--)b[j] = (j+1<n &&b[j+1]>a[j]) ?b[j+1]:a[j];
    int ans=0,j=0;
    for(int i=0;i<n;i++){
        for(;j<n;j++){
            if (b[j]>=a[i])continue;
            else break;
        }
        ans = max(ans,j-i-1);
    }
    cout<<ans<<endl;
}

answer2:
用栈的处理方式

我们这样如果 a[i1]>=a[i2]且i1>i2那a[i1]就没有必要进行比较,因为如果j对i1成立,必然对i2成立,且j-i2>j-i1.
所以我们如果将a数组中的递减序列下标做成一个栈s。

然后我们逆向遍历a下标为j,
如果a[j]>=a[s.top()],就pop栈顶,并更新ans = max(ans,j-s.top())为最大的差值,直到a[j]<a[s.top()]。
这样ans为最后的结果。

为何栈弹出后不用再压入栈中,与上种方法类似。


#include<iostream>
#include<stack>
using namespace std;

int main(){
    int n;
    stack<int> s;
    int a[1000],b[1000];
    cin>>n;
    for(int i = 0;i<n;i++)cin>>a[i];
    s.push(0);
    for(int i=1;i<n;i++){
        if (a[i]<s.top())
            s.push(i);
    }

    int ans=0;
    for(int j=n-1;j>=0;j--){
        if(!s.empty() && a[j]>=a[s.top()]){
            ans = max(ans,j-s.top());

            s.pop();
            j++;
        }
    }
    cout<<ans<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值