算法之 数组的“距离”

来源:互联网 发布:淘宝联盟靠谱吗 编辑:程序博客网 时间:2024/06/06 08:31

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谁先到达,都不会错过最优解,于是上述算法是正确的。

0 0
原创粉丝点击