直接遍历得到O(n),二分查找O(logn)http://ac.jobdu.com/problem.php?pid=1386
直接二分,以下图所示情况来进行说明
按照s[mid] 在图中的位置在前半部分还是后半部分分成两大类,即(s[beg] 与s[mid]大小的比较)
1. 如果s[beg] <= s[mid], 且s[mid] <= s[end] 对应于图1所示情况,图3是该情况的特例
2. 如果s[beg] <= s[mid], 且s[mid] > s[end] 对应于图2所示的情况,且mid落在了图2的前半部分
3. 如果s[beg] > s[mid],且s[mid] >= s[end] (按照题目中的描述,不会出现s[mid] > s[end]的情况)对应图4所示的情况,且mid落在了图4的后半部分
4. 如果s[beg] > s[mid],且s[mid] < s[end] 对应与图2所示的情况,且mid落在了图2的后半部分
代码如下:
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
int s[1000010];
int find(int beg,int end){
int mid;
while(beg <= end){
if(beg == end)
return s[beg];
if(beg + 1 == end)
return min(s[beg],s[end]);
mid = (beg + end) >> 1;
if(s[beg] <= s[mid]){
if(s[mid] <= s[end]){
end = mid - 1;
}
else{
beg = mid;
}
}
else if(s[beg] > s[mid]){
if(s[mid] >= s[end]){
beg = mid + 1;
}
else{
end = mid;
}
}
}
}
int main(){
int n,key;
while(scanf("%d",&n) != EOF){
for(int i = 0;i < n;i++){
scanf("%d",&s[i]);
}
printf("%d\n",find(0,n-1));
}
/// system("pause");
}
14/09-07代码更新如下:
/*
特别注意
5
1 0 1 1 1 (beg,mid,end位置的数字相等的情况下)
下面代码中的
if(s[mid] <= s[end] && s[mid] >= s[beg]){
end = mid - 1;
}
可以解决该问题
*/
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstdlib>
#include <cstring>
int s[1000010];
int find(int beg,int end){
while(end - beg > 1){
int mid = (beg + end) >> 1;
if(s[mid] <= s[end] && s[mid] >= s[beg]){
end = mid - 1;
}
else if(s[mid] <= s[beg] && s[mid] >= s[end]){
beg = mid + 1;
}
else if(s[mid] >= s[beg] && s[mid] >= s[end]){
beg = mid;
}
else if(s[mid] <= s[beg] && s[mid] <= s[end]){
end = mid;
}
}
return min(s[beg],s[end]);
}
int main(){
int n;
while(scanf("%d",&n) != EOF){
for(int i = 0;i < n;i++){
scanf("%d",&s[i]);
}
printf("%d\n",find(0,n-1));
}
//////////system("pause");
}
另外何海涛的博客中给出了另外一种解法,但是该解法不是严格意义上的O(logn)http://zhedahht.blog.163.com/blog/static/25411174200952765120546/
《剑指offer》一书中有详细解答,作者采用了两个指针的做法,第一个指针移到前半段的最大节点,第二个指针移动到后半个分支的最小节点,但是该算法解决不了当
s[beg] == s[mid] && s[mid] == s[end] 的情况,在该情况下作者采用了顺序遍历的方法.
代码如下:
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
int s[1000005];
int find(int beg, int end){
int res = beg;
while(s[beg] >= s[end]){
if(end - beg == 1){
res = end;
break;
}
int mid = (beg + end)/2;
if(s[beg] == s[mid] && s[beg] == s[end]){
// 顺序查找
int result = s[beg];
for(int i = beg + 1;i <= end;i++){
if( result > s[i] )
result = s[i];
}
return result;
}
if(s[mid] <= s[end]){
end = mid;
}else if(s[mid] >= s[beg]){
beg = mid;
}
}
return s[res];
}
int main(){
int n,key;
while(scanf("%d",&n) != EOF){
for(int i = 0;i < n;i++){
scanf("%d",&s[i]);
}
if(n != 0)
printf("%d\n",find(0,n-1));
}
}