给定一个数组A,当中有一个位置被称为Magic Index,含义是:如果i是Magic Index。则A[i] = i。

如果A中的元素递增有序、且不反复,请给出方法,找到这个Magic
Index。更进一步。当A中同意有反复的元素,该怎么办呢?

没有反复元素的情况

一些同学在遇到这个题目的时候,往往会认为比較简单。扫描一遍,不就ok了么?O(n)的。非常easy呀。但是,大家要注意到,另一个条件没实用:A中的元素是有序递增的。

这个条件,并非放在这里迷惑大家的。而是有更大的作用的。

这个时候,该怎样想呢?O(n)不是最好的方法,更好的是什么呢?怎么利用数组有序呢?在有序的数组中查找一个满足特定元素的条件。我们一般会想到二分查找。 我们来回想一下二分查找,对于要查找的目标t,我们首先与数组中间的元素比較,假设t大于中间的元素,则在右半部分继续查找;假设t小于中间的元素,则在左半部分,继续查找。

那么。我们的题目可以利用上述的思想呢?我们来看一个详细的样例:

0    1    2    3    4    5    6
-10 -5 1 2 4 10 12

mid=3。A[mid] = 2,即A[mid] < mid。接下来,我们应该在哪一边查找呢?我们知道数组的元素是递增有序,且不反复的。也就是说,在A[mid]左边的元素,比A[mid]都要小。没有反复,意味着什么呢?每向左移动一位,至少减1。所以,在mid左边,不可能有一个i,A[i]=i的。假设有。依据前面的分析。我们知道A[mid] - A[i] >= mid - i, 假设A[i] = i。则,A[mid] >= mid, 这与事实A[mid] < mid相悖。所以,接下来,仅仅能在右边进行查找。

代码与二分查找也非常像。

详细代码例如以下:

int MagicIndex(vector<int>& data)
{
int begin = 0,end = data.size()-1;
while(begin <= end)
{
int mid = begin + ((end - begin) >> 1);
if(data[mid] > mid)end = mid -1;
else if(data[mid] < mid)begin = mid + 1;
else return mid;
}
return -1;
}

有反复元素的情况

假设数组A中,有反复元素,是什么情况呢?经过前面的分析。我们知道,是否有反复的主要区别在,数组的元素从右到左进行递减,每次不一定至少是1了。有可能是0了。

让我们直观的看一下影响吧。

0    1    2    3    4    5    6
-10 2 2 2 9 10 12

看上面的数组,相同A[mid] < mid。我们应该继续查右边么?显然,右边并不存在Magic Index。查找右边,就会找不到这种Magic Index。

此时,应该怎样处理呢?我们无法确定,Magic Index是在左边,还是在右边了。那就两边都递归进行处理吧。

在这里另一个小技巧,我们就是要分别递归处理[0, mid - 1]和[mid + 1, end](end是数组长度-1)么?我们看一个详细的样例:

0      1    2    3    4    5     6    7     8
-10 2 2 2 2 10 12 15 20

这个样例,当我们进行左半部分递归处理的时候。须要考虑的范围是[0, 3]。可实际上。我们仅仅须要考虑[0, 2]。原因是,数组元素在mid=4的左边的值都要小于或者等于A[mid]=2,所以最大的一个有可能是Magic Index的。就是index为A[mid]的情况。所以,这时右边的边界应该是min(mid - 1, A[mid])。

那么,右边的情况呢?例如以下样例:

0      1    2    3    4    5     6    7    8
-10 2 2 2 9 10 12 15 20

此时,要在右半部分进行查找。范围通常是[5, 8]。可是,因为数组有序,后面的值,一定是大于等于A[mid]=9的。

所以。有可能是Magic Index的最小Index是9,也就是说右边的递归。应该是从索引为9的位置開始。此例,就意味着,无需处理右边了。

详细代码例如以下:

int MagicIndexDup(vector<int>& data,int begin,int end)

{

if(begin > end)return -1;

int mid = begin + ((end - begin) >> 1);

if(data[mid] == mid)return mid;

int res = MagicIndexDup(data,begin,min(mid-1,data[mid]));//递归左边

if( res == -1)res = MagicIndexDup(data,max(mid+1,data[mid]),end);//递归右边

return res;

}

int MagicIndexDup(vector<int>& data)

{

return MagicIndexDup(data,0,data.size()-1);

}

最新文章

  1. 自定义BadgeView
  2. java.lang.NullPointerException 空指针异常
  3. 在自己的网站上实现QQ授权登录
  4. mysql slow log分析工具的比较
  5. 问题-Delphi记忆工程打开的单元(XE2设置项)
  6. Introduction to Big Data with Apache Spark 课程总结
  7. Arduino VS. Raspberry Pi VS. Beaglebone Black
  8. JDBC (一)
  9. Web Api 过滤器之 AuthorizationFilter 验证过滤器
  10. CentOS下RPM方式安装MySQL5.6(转载)
  11. Java课程课后作业190315之从文档中读取随机数并得到最大连续子数组
  12. 通过一篇YAML来学习YAML
  13. 提交SR的一些小技巧
  14. 题解——洛谷P3390 【模板】矩阵快速幂(矩阵乘法)
  15. HDU 1431 素数回文 离线打表
  16. maven单测生成覆盖率报告---Jacoco的使用
  17. Python: Flask框架简单介绍
  18. jquery跨域请求事例
  19. 【性能测试】:操作NMON的shell脚本
  20. TensorFlow(实战深度学习框架)----深层神经网络(第四章)

热门文章

  1. rsync实时同步mysql数据库
  2. 2019-03-18 Python time 将2015年11月20日转换为2015-11-20
  3. centos7下搭建solr服务器
  4. 【codeforces 794C】Naming Company
  5. HDU 4339 Contest 4
  6. Android动态加载字节码
  7. git batch
  8. m_Orchestrate learning system---七、如何快速学好前端
  9. zzulioj--1708--01串也疯狂之光棍也有伴(dp)
  10. 在vmware下为oracle RAC 创建共享存储的总结