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;
}