博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
careercup-递归和动态规划 9.3
阅读量:6731 次
发布时间:2019-06-25

本文共 2517 字,大约阅读时间需要 8 分钟。

9.3 在数组A[0...n-1]中,有所谓的魔术索引,满足条件A[i]=i。给定一个有序整数数组,元素值给不相同,编写一个方法,在数组A中找出一个魔术索引,若存在的话。

进阶:

如果数组元素有重复值,又该如何处理。?

解法一,选择蛮力法,我们可以直接迭代访问整个数组,找出符号条件的元素。

int magicSlow(int arr[],int n){    if(n==0)        return -1;    int i;    for(i=0;i

解法二:既然给的数组是有序的,我们理应充分利用这个条件。

你看你会发现这个问题与经典的二分查找问题非常相似。充分运用匹配法,就能找到适当的算法,我们又该怎样运用二分查找法呢?

在二分查找中,要找出元素k,我们会先拿它跟数组中间的元素x比较,确定k位于x的左边还是右边。

以此为基础,是否通过检查中间元素就能确定魔术索引的位置?

通过比较A[mid]<mid,可以确定该魔术索引一定在mid的右边,因此left=mid+1;

如果A[mid]>mid,可以取得该魔术索引一定在mid 的左边,因此right=mid-1;

算法如下:

int magicQuick(int arr[],int n){    if(n==0)        return -1;    int mid;    int left=0;    int right=n-1;    while(left<=right)    {        mid=(left+right)/2;        if(mid==arr[mid])            return mid;        else if(mid

进阶:

如果存在重复元素,前面的算法就会失效。以下面的数组为例:

-10 -5 2 2 2 3 4 7 9 12 13

  0   1  2 3 4 5 6 7 8 9 10 11

看到A[mid]<mid时,我们无法判定魔术索引位于数组哪一边。它可能在数组右侧,跟前面一样。或者,也可能在左侧(在本例中的确在左侧)。

它有没有可能在左侧的任意位置呢?不可能。由A[5]=3可知,A[4]不可能是魔术索引。A[4]必须等于4,其索引才能成为魔术索引,但数组是有序的,故A[4]必定小于A[5]。

事实上,看到A[5]=3时按照前面的做法,我们需要递归搜索右半部分。不过,如搜索左半部分,我们可以跳过一些元素,值递归搜索A[0]到A[3]的元素。A[3]是第一个可能成为魔术索引的元素。

 

综上:我们得到一种搜索模式,先比较midIndex和midValue是否相同。然后,若两者不同,则按如下方式递归搜索左半部分和右半部分。

左半部分:搜索索引从start到min(midIndex-1,midValue)的元素。

右半部分:搜索索引从max(midIndex+1,minValue)到end的元素。

可以看做前面的基础上求左右两边的交集,例如A[mid]<mid,需要搜索mid左边的部分元素,即区间从start到min(midIndex-1,midValue)的元素和mid右边的全部元素。

A[mid]>mid,需要搜索mid左边的全部元素和右边的部分元素,即区间从max(midIndex+1,minValue)到end,然后两者求交集,就得到上面的区间了。

算法如下:

int magicHelper(int arr[],int n,int l,int r){    if(l>r||l<0||r>=n)        return -1;    int mid=(l+r)/2;    if(mid==arr[mid])        return mid;    int rightindex=min(mid-1,arr[mid]);    int left=magicHelper(arr,n,l,rightindex);    if(left>=0)        return left;    int leftindex=max(mid+1,arr[mid]);    int right=magicHelper(arr,n,leftindex,r);    return right;}//有重复元素int magicFast(int arr[],int n){    if(n==0)        return -1;    return magicHelper(arr,n,0,n-1);}

完整代码:

#include
using namespace std;int magicSlow(int arr[],int n){ if(n==0) return -1; int i; for(i=0;i
r||l<0||r>=n) return -1; int mid=(l+r)/2; if(mid==arr[mid]) return mid; int rightindex=min(mid-1,arr[mid]); int left=magicHelper(arr,n,l,rightindex); if(left>=0) return left; int leftindex=max(mid+1,arr[mid]); int right=magicHelper(arr,n,leftindex,r); return right;}//有重复元素int magicFast(int arr[],int n){ if(n==0) return -1; return magicHelper(arr,n,0,n-1);}int main(){ int arr[10]={-1,0,1,2,3,4,5,6,7,9}; cout<
<

 

转载地址:http://psfqo.baihongyu.com/

你可能感兴趣的文章
A damn at han’s Windows phone book 笔记(6:page navigation & data binding)
查看>>
【luogu 2529】【SHOI 2001】击鼓传花
查看>>
C# PDF 全攻略
查看>>
android第二次作业
查看>>
java流类基础练习。
查看>>
kill-9 kill-3
查看>>
登陆密码加密
查看>>
MVC过滤器
查看>>
5天玩转C#并行和多线程编程 —— 第四天 Task进阶
查看>>
《你的灯亮着吗》——读后总结
查看>>
LoadRunner FAQ2
查看>>
Sql Server之旅——第五站 确实不得不说的DBCC命令
查看>>
用适配器模式处理复杂的UITableView中cell的业务逻辑
查看>>
HOG特征-理解篇
查看>>
结构类模式(四):装饰(Decorator)
查看>>
java面试题
查看>>
使用两个 Windows 窗体 DataGridView 控件创建一个主/从窗体
查看>>
111、Android 高仿 频道管理---(可以拖动的GridView)附源码DEMO (转载)
查看>>
l2正则化
查看>>
Atitit 视图状态ViewState)的原理与管理
查看>>