题意:
给你一个长度为n的数组 ,让你找到数组中最长的一个连续子段
,使得这个子段之间存在一个
,使得
且
严格递增 且
严格递减,求出这个子段的长度即可。
解法一(枚举点k,暴力统计答案,不可AC)
我们可以从左到右依次枚举这个点 ,然后尝试以
为最高点依次向左右两边扩展,最后统计答案取最大值即可。
代码:
class Solution { public: int getMaxLength(int n, vector<int>& num) { int ans=0;//最终答案 for(int k=0;k<num.size();k++){//枚举最高点k int lcnt=0; int idx=k-1; while(idx>=0&&num[idx]<num[idx+1]){//向左扩展 lcnt++; idx--; } idx=k+1; int rcnt=0; while(idx<num.size()&&num[idx]<num[idx-1]){//向右扩展 rcnt++; idx++; } if(lcnt>0&&rcnt>0){//存在金字塔 ans=max(ans,lcnt+rcnt+1); } } return ans; } };
时间复杂度: ,我们枚举最高点
的代价是
的,向左、向右扩展的代价也都是
的,故总的时间复杂度为
空间复杂度: ,我们并没有另外开辟空间,故空间复杂度为
解法二(递推法,可AC)
我们设 表示以第
个数字为最高点,向左扩展最长的长度。
我们设
表示以第
个数字为最高点,向右扩展最长的长度。
我们举个例子:
同理:
我们两遍循环求出上面的
代码:
class Solution { public: int f[1000001],g[1000001]; int getMaxLength(int n, vector<int>& num) { memset(f,0,sizeof f);//多测清空 memset(g,0,sizeof g); //我们把数组下标0~num.size()-1 偏移到 1~num.size() f[1]=1; for(int i=2;i<=num.size();i++){ if(num[i-2]<num[i-1]){//如果当前这个比左边的大,可以接上去 f[i]=f[i-1]+1; }else{ //否则单独成为一个 f[i]=1; } } g[num.size()]=1; for(int i=num.size()-1;i>=1;i--){ if(num[i]<num[i-1]){//如果右边的比当前的小,可以接上去 g[i]=g[i+1]+1; }else{ //否则单独成为一个 g[i]=1; } } int ans=0; for(int i=1;i<=num.size();i++){ if(f[i]>1&&g[i]>1){//如果能够组成金字塔形 ans=max(ans,f[i]+g[i]-1); } } return ans; } };
时间复杂度: ,我们递推求解
都是
的,枚举最高点计算答案也是
的,故总的时间复杂度为
空间复杂度: ,
都是
级别的,故总的空间复杂度为