一个循环有序数组([7,7,8,9,1,2,3,6,7,7,7]),不知道其最大值的位置,要查找任一数值的位置。要求算法时间复杂度为log2(n)。
解这道题的有两种:
1. 找到分界点,将数组分为两段, 然后用有序数组的二分查找方法。
2. 直接二分查查找法思想就是,比较a[mid], a[end], k三者的大小,来确定下次查找是在mid的右边还是左边。 看了网上很多的解法,很多都没有处理好a[mid] == a[end]时情况,导致当数组为:{7,7,7,7,7,7,7,7,9,12,1,7} 或者{7,7,9,1,2,3,7,7,7,7,7,7,7,7} 的时候,测试不通过。
以下代码经过多次测试,验证无误。欢迎各位同仁多多指证。
#include <stdio.h>
//查找分界点,数组中最大元素的位置
int find_max(int *a, int len)
{
if(len == 1)
{
return 0;
}
int left = 0;
int right = len - 1;
int mid;
while(left<=right)
{
mid = (left + right) / 2;
printf("left=%d, right=%d, mid=%d\n", left, right,mid);
if(a[mid] > a[mid+1])
{
return mid;
}
else if(a[mid] > a[len-1])
{
left = mid + 1;
}
else if(a[mid] < a[len-1])
{
right = mid - 1;
}
else //a[mid]=a[len-1]时,无法直接判断 比如:[7,7,7,7,7,7,8,1,7] [8,9,1,7,7,7,7,7,7]
{
int i = mid + 1;
int flag = 0;
while(i<=right)
{
if(a[i] > a[len-1])
{
flag = 1;
break;
}
++i;
}
if(flag == 1) // [mid+1,right] 区间内有大于末尾元素的值
{
left = i;
}
else
{
right = mid - 1;
}
}
}
return len-1;
}
int find(int *a, int len, int k)
{
int left = 0;
int right = len - 1;
int mid = -1;
while(left<=right)
{
mid = (left + right) / 2;
//printf("left=%d, right=%d, mid=%d, val_mid=%d, val_right=%d, ",left, right, mid, a[mid], a[right]);
int val_mid = a[mid];
int val_end = a[len - 1]; // 也可以 int val_end = a[right], 不过性能应该要差点
if(val_mid == k)
{
return mid;
}
else if(val_mid > k)
{
if(val_mid > val_end)
{
if(val_end >= k)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
else if(val_mid < val_end)
{
right = mid - 1;
}
else
{
int i = mid + 1;
int flag = 0;
while(i<=right)
{
if(a[i] < val_mid)
{
flag = 1;
break;
}
++i;
}
if(flag == 1)
{
left = i;
}
else
{
right = mid - 1;
}
}
}
else
{
if(val_mid < val_end)
{
if(val_end >= k)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
else if(val_mid > val_end)
{
left = mid + 1;
}
else
{
int i = mid + 1;
int flag = 0;
while(i<=right)
{
if(a[i] > val_mid)
{
flag = 1;
break;
}
++i;
}
if(flag == 1)
{
left = i;
}
else
{
right = mid - 1;
}
}
}
}
return -1;
}
int main ()
{
//int a[] = {7,7,7,7,7,7,7,7,9,12,1,7};
int a[] = {7,7,9,1,2,3,7,7,7,7,7,7,7,7};
//int a[] = {1,2,3,4,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7};
int len = sizeof(a) / sizeof(int);
int k =1;
int index = find(a, len ,k);
if(index == -1)
{
printf("not find\n");
}
else
{
printf("len=%d, index=%d, a[index]=%d\n", len, index, a[index]);
}
return 0;
}