百度一道算法题
Q:一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它。能否只用一个额外数组和少量其它空间实现。
A:如果我们遍历数组是对于每一个元素都要往左和往右判断是否符合条件,则时间复杂度为O(n^2)。既然可以用辅助数组,就可以利用空间换时间的办法进行优化。
原数组为a[n],定义一个辅助数组为b[n]。
首先我们求左边数都小于等于它的元素,因为左边数都小于等于它,所以左边数的最大值也小于等于它,所以我们一边遍历a一边保存经过的子数组的最大值,首先设定max=a[0],从a[1]到a[n-2](因为最后一个数必然不是我们要求的数)的遍历过程中,如果当前元素大于等于max,则更新max,并且将该元素添加至数组b中。这样一趟遍历下来,数组b中保存的就是左边数都小于等于它的元素,并且是递增顺序。这样,我们要求的结果必然是数组b的子集。
然后继续考虑右边数都大于等于它的元素,和刚才的过程相对,我们设定min=a[n-1],从a[n-2]到a[1]的遍历过程中,如果当前元素小于等于min,则更新min,并且当前元素等于b数组的当前最后一个元素,则说明该元素符合题目要求,输出,并且将b数组当前最后一个元素更新为倒数第二个元素;如果当前元素大于min,而等于b数组的当前最后一个元素,则说明该元素只符合一项条件,只更新b数组当前最后一个元素即可。
#include <iostream> using namespace std; void Func(int* arr,int n) { if(!arr || n<=2) return; int *b=new int[n]; int cnt=0; int max=arr[0]; for(int i=1;i<n-1;++i) { if(arr[i]>max) { max=arr[i]; b[cnt++]=arr[i]; } } --cnt; int min=arr[n-1]; for(int i=n-2;i>0 && cnt>=0;--i) { if(arr[i]<min) { if(arr[i]==b[cnt]) { cout <<arr[i]<<" "; cnt--; } min=arr[i]; } else { if(arr[i]==b[cnt]) cnt--; } } delete [] b; } int main() { int n; while(cin >>n) { int *a=new int[n]; for(int i=0;i<n;++i) cin >>a[i]; Func(a,n); cout <<endl; } return 0; }