高效的算法找出中间全部A[i] = i的下标
  给定一个排好升序的数组A[1]、A[2]、……、A[n],其元素的值都两两不相等。
给定一个排好升序的数组A[1]、A[2]、……、A[n],其元素的值都两两不相等。
请设计一高效的算法找出中间全部A[i] = i的下标。并分析其复杂度。
解析:首先分析一下这个数组。如果当中某个位置的A[i] = i,那么能够肯定的值,之前的A[x] > x,之后的A[x] < x。另一个显而易见的性质就是中间的A[i]=i一定是连续存在的。不可能跨区域存在。由于这个数组是升序的。
我给出的方法是二分查找,详细的做法是:我们如果一个新数组B。其元素是A[i] - i的值,这种话。B[i] = 0的时候A[i] = i,并且把B数组划分成了三个部分,左边的小于零的区域,中间的等于零的区域,右边的大于零的区域。
我第一次的想法是:二分搜索这个想象中的新数组,找到值为零的下标。可是这个下标不一定是最左边的满足条件的下标,所以我们还须要写一个while来往左移动这个下标,直到找到最左边的符合条件的下标,例如以下代码(如果已经通过二分查找找到了符合条件的一个下标idx):
| 
1 
2 | while(A[idx-1]
 == (idx-1))     idx--; | 
这种话其时间复杂度就是O(logn) + O(n),还是属于On)的范畴。
后来我想到。为什么仅仅去随机命中一个目标下标呢!如果二分查找这个数据的边界的话,就能直接得到最左边符合条件的下标了!事实上二分查找不仅仅适用于对一个元素的搜索。也能够用于两个、三个特定相对位置元素的搜索。每次查找的时候,如果当前位置是mid,那么仅仅要推断当前A[mid] - mid是否小于零。以及后一个元素A[mid+1] - (mid+1) == 0即可了。
#include 
 <iostream> usingnamespace std;  intBinarySearch(intcc[], intlen) {    intl
 = 0, r = len, mid;    while(l
 <= r)    {       mid
 = l + ((r-l) >> 1);       if(mid
 == 0 && cc[mid] == mid)   //
 若数组一開始就符合条件          return0;       //
 若满足条件的下标不是从0開始。则边界是前一个<0,且后一个=0       if(cc[mid]-mid
 < 0 && cc[mid+1]-(mid+1) == 0)          returnmid+1;       //
 二分查找边界:前一个<0,且后一个=0       if(cc[mid]
 - mid >= 0)          r
 = mid-1;       else          l
 = mid+1;    }    return-1; }    int main() {    //
 int cc[] = {0, 1};    //
 int cc[] = {0, 1, 2, 3, 4, 5, 6, 7};    //
 int cc[] = {-9, -8, -4, -2, 4, 5, 9};    //
 int cc[] = {-5, -4, -3, 5, 6, 7};    intlen
 = sizeof(cc)/sizeof(int);    intidx
 = BinarySearch(cc, len);    if(idx
 != -1)    {       while(cc[idx]
 == idx)       {          printf("%d
 ",
 idx);          idx++;       }    }    else    {       printf("Not
 found\n");    }       getchar();    return0; }  
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号