Description:
给定数组A[0---n-1],找出数组中的max(j - i),其中 i< j && A[i] < A[j].这里的最大的(j-i)的值就是数组的“距离”。
方法一:直接枚举,O(n^2).
方法二:伴随数组 + 排序, O(n*logn)
此处的伴随数组的定义是: A : 3 2 1 4 那么数组A 的伴随数组即是
A : 3 2 1 4
index: 0 1 2 3 伴随数组即为 [(3,0),(2,1),(1,2),(4,3)]其中元素为pair。
接着,对排序之后的数组首先进行预处理,如下:
A : 4 3 2 5 1 3 2 3 == 》 A : 1 2 2 3 3 3 4 5 == 》 A : 1 2 2 3 3 3 4 5
index : 0 1 2 3 4 5 6 7 == 》 index: 4 3 6 1 5 7 0 2 == 》 index: 7 7 7 7 7 7 2 2
注意:此处必须考虑数组中的元素可能有相同的,也就是在更新j-i的值的时候必须考虑此时的A[i] 与A[j]是否相等。
方法3: O(N)
A : 4 3 5 2 1 3 2 3
lMin : 4 3 3 2 1 1 1 1 lMin[i] : A[0...i]的最小值
rMax : 5 5 5 3 3 3 3 3 rMax[i] : A[j...n-1]的最大值
代码为:
//O(N^2) int maxIJ1(const vector<int> &A) { const int n = A.size(); if(n<2) return -1; int maxdiff=0; for(int i=0; i<n; ++i) { for(int j=n-1;j>i;--j) { //maxdiff=max(maxdiff,j-i); if((A[j]>A[i]) && (j-i)>maxdiff) { maxdiff=j-i; break; } } } return maxdiff; } //O(N*logN) int maxIJ2(const vector<int> &A) { const int n = A.size(); if(n<2) return -1; typedef pair<int,int> P; vector<P> tmp(n); for(int i=0;i<n;++i) tmp[i]=make_pair(A[i],i); sort(tmp.begin(), tmp.end()); //preprocessing the index vector<int> rMaxIndex(n,0); rMaxIndex[n-1]=tmp[n-1].second; for(int i=n-2;i>=0;--i) rMaxIndex[i]=max(rMaxIndex[i+1],tmp[i].second); int maxdiff=0; for(int i=0;i<n;++i) { int left=tmp[i].second; int right=rMaxIndex[i]; assert(A[left]<=A[right]); if(A[left]!=A[right] && (right-left)>maxdiff) //必须首先判断是否相等。用来处理数组中有相同的元素的情况 maxdiff=right-left; } return maxdiff; } //O(N) int maxIJ(const vector<int> &A) { const int n = A.size(); if(n<2) return -1; vector<int> lMin(n,0),rMax(n,0); lMin[0]=A[0]; rMax[n-1]=A[n-1]; for(int i=1; i<n; ++i) lMin[i] = min(lMin[i-1],A[i]); for(int i=n-2; i>=0; --i) rMax[i] = max(rMax[i+1],A[i]); int maxdiff=0; int i=0,j=0; while(i<n && j<n) { if(lMin[i]<rMax[j]) { maxdiff=max(maxdiff,j-i); j++; } else { ++i; } } return maxdiff; }
关于O(N)的算法的正确性的证明:
Obeservation: lMin与rMax都是非递增的。
假设i*,j*是最优解,分两种情况讨论:
1 假设i先到达i*,j还没到,则此时如果i还要再移动的话,那么也就是说lMin[i]>rMax[j],又由于rMax的非递增,rMax[j]>=rMax[j*],则
lMin[i*]>rMax[j]>rMax[j*],与i*,j*是最优解矛盾。
2 假设j先到达j*,i还未到,(那么我们此时要证明的是j不会再移动了),如果j此时要移动的话,那么lMin[i]<rMax[j*],又由于i*与j*是最优解,那么就一定有lMin[i*]<rMax[j*],此时我们将i*换做i可以得到更优的解,与假设矛盾。
因此,无论ij谁先到达,都不会错过最优解,于是上述算法是正确的。