Question

A magic index in an array A[1...n-1] is defined to be an index such that A[i] = i. Given a sorted array of distinct integers, write a method to find a magic index, if one exists, in array A. FOLLOW UP What if the values are not distinct?

给定一个数组A,其中有一个位置被称为Magic Index,含义是:如果i是Magic Index,则A[i] = i。假设A中的元素递增有序、且不重复,请给出方法,找到这个Magic Index。更进一步,当A中允许有重复的元素,该怎么办呢?

Solution for distinct value

一些同学在遇到这个题目的时候,往往会觉得比较简单。扫描一遍,不就ok了么?O(n)的。很简单呀。可是,大家要注意到,还有一个条件没有用: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相悖。所以,接下来,只能在右边进行查找。代码与二分查找也很像。

  1. #include<iostream>
  2. using namespace std;
  3.  
  4. int magicIndex(int a[],int n)
  5. {
  6. int low=,high=n-,mid;
  7. while(low<=high)
  8. {
  9. mid=(low+high)/;
  10. if(a[mid]==mid)
  11. {
  12. return mid;
  13. }
  14. else if(a[mid]<mid)
  15. {
  16. low=mid+;
  17. }
  18. else //a[mid]>mid
  19. {
  20. high=mid-;
  21. }
  22. }
  23. return -;
  24. }
  25. int main()
  26. {
  27. int a[]={-,-,,,,,};
  28. int n=sizeof(a)/sizeof(a[]);
  29. int result=magicIndex(a,n);
  30. cout<<result<<endl;
  31. }

Solution for not distinct value

如果数组A中,有重复元素,是什么情况呢?

我们假设不要二分思想,从遍历的角度看:从头到尾走一边如果a[i]等于i的话,找到了;如果大于i的话,让i=a[i],不然i++继续找。这样最差的情况才是O(n)
至于为什么可以让i=a[i],原因由于数列是递增的,所以数组元素在{i, a[i]}的区间中,肯定不可能存在magic index。这样看上去是不是跳跃着前进啊。:) 理解上面的话很重要,其实如果a[i]>i的话,由于相差a[i]-i个位置,所有[i,a[i]]中间的元素都不可能相等。

 1 int find_magic_index (int *list, int count) {
 2     int i=0;
 3     while (i<count) {
 4         if (list[i] == i)
 5             return i;
 6         else if (list[i] > i)
 7             i = list[i];
 8         else
 9             i++;
10     }
11     return -1;
12 }
 

经过前面没有重复元素的分析,我们知道,是否有重复的主要差别在,数组的元素从右到左进行递减,每次不一定至少是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 13 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 13 20

此时,要在右半部分进行查找,范围一般是[5, 8]。但是,由于数组有序,后面的值,一定是大于等于A[mid]=9的。所以,有可能是Magic Index的最小Index是9,也就是说右边的递归,应该是从索引为9的位置开始。此例,就意味着,无需处理右边了。

  1. #include<iostream>
  2. using namespace std;//有重复元素
  3. int findMagicIndex(int a[],int low,int high)
  4. {
  5. int mid=(low+high)/;
  6. if(a[mid]==mid)
  7. {
  8. return mid;
  9. }
  10. else if(a[mid]<mid)
  11. {
  12. return findMagicIndex(a,low,a[mid]);
  13. }
  14. else //a[mid]>mid
  15. {
  16. return findMagicIndex(a,a[mid],high);
  17. }
  18. }
  19.  
  20. int main()
  21. {
  22.  
  23. int a[]={-,,,,,,,,};
  24. int n=sizeof(a)/sizeof(a[]);
  25. int result=findMagicIndex(a,,n-);
  26. cout<<result<<endl;
  27. }

输出:2.

参考:https://gist.github.com/sing1ee/5982361

数组Magic Index的更多相关文章

  1. Magic Index 寻找数组中A[i]=i的位置(原题转自微信号待字闺中)

    有一个有意思的题目叫做Magic Index:给定一个数组A,其中有一个位置被称为Magic Index,含义是:如果i是Magic Index,则A[i] = i.假设A中的元素递增有序.且不重复, ...

  2. [CareerCup] 9.3 Magic Index 魔法序号

    9.3 A magic index in an array A[0.. .n-1] is defined to be an index such that A[i] = i. Given a sort ...

  3. 算法----Magic Index

    给定一个数组 A,如果 某个下标 i, 满足 A[i] = i, 则 i 称为 Magic Index. 现在假设 A 中的元素是递增有序的.且不重复,找出 Magic Index. 更进一步,当数组 ...

  4. 待字闺中之Magic Index 分析

    给定一个数组A,当中有一个位置被称为Magic Index,含义是:如果i是Magic Index.则A[i] = i. 如果A中的元素递增有序.且不反复,请给出方法,找到这个Magic Index. ...

  5. [8.3] Magic Index

    A magic index in an array A[0...n-1] is defined to be an index such that A[i] = i. Given a sorted ar ...

  6. 将两个数组相同index的value合并成一个新的value组成一个新的数组

    将两个数组相同index的value合并成一个新的value组成一个新的数组 前提: 这两个数组的长度相同 生成后的新数组长度也相同 返回值都是对象 把rows对象的key和value弄成两个数组, ...

  7. MVVM架构~knockoutjs系列之数组的$index和$data

    返回目录 已经写了很多knockoutjs的文章了,今天在review代码时,忽然看到一个问题,在knockout环境下,如何遍历一个简单的数组?对于遍历对象组件的数组来说,很容易,直接foreach ...

  8. 知道一个数组某个index对应的值 不知道下标的情况下删除该值

    for (index,item) in Arr.enumerated() { if item == item { Arr.remove(at: index) } } 更好的方法是用数组的filter尾 ...

  9. 数组根据index拆分和查询下标

    private class ArrayTool<T> { /// <summary>查询值在数组中的下标</summary> /// <param name= ...

随机推荐

  1. JSON对象和字符串的互相转换

    1.JSON.parse; 作用:将JavaScript对象表示法的JSON字符串转换为对象(字符串转对象) 语法:JSON.parse(text [, reviver]) text    必选. 一 ...

  2. EOFError:EOF when reading a line

    Sublime2编译Python程序EOFError:EOF when reading a line: 是因为Sublime2对于python中运行含有input或者raw_input的python代 ...

  3. 学习head first python一书用到的程序(安卓开发/GAE)

    学习head first python一书用到的程序资料等文件 包括源码.电子书.一些安卓开发.gae开发程序文件,一些程序比较老,都不好找了(找了很久才收集齐),所以发上来,留给需要的人吧. 包括: ...

  4. LSD-FET430UIF与MSP-FET430UIF

    成功的破解了没人研究的东西很有成就感!世界需要这样的人!!!LSD-FET430UIF与MSP-FET430UIF?什么是MSPF149?网上查了很多这方面的资料,都没有,最后凭借我阅读PDF的精神和 ...

  5. 未能加载文件或程序集 Microsoft.ReportViewer.Common, Version=11.0.0.0

    原文:未能加载文件或程序集 Microsoft.ReportViewer.Common, Version=11.0.0.0 System.IO.FileNotFoundException: 未能加载文 ...

  6. python手记(51)

    python通过声音将文件内容隐藏,实现原理是将文件的内容分别插入到声音文件的不同位置中做为当次采样的数据,目前是对英文文本文档加解密 #!/usr/bin/env python # -*- codi ...

  7. 练习3.20 a 将中缀表达式转换为后缀表达式

    //将中缀表达式转换为后缀表达式 int main() { ; ]={,,,,,,,}; char tmp; PtrToStack s; s = CreateStack( MaxSize ); ) { ...

  8. 全国计算机等级考试二级教程-C语言程序设计_第7章_函数

    函数执行,从右到左执行 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> main() ...

  9. 04737_C++程序设计_第4章_类和对象

    例4.1 描述点的Point类. 例4.2 根据上面对Point类的定义,演示使用Point类的对象. #define _SCL_SECURE_NO_WARNINGS #include <ios ...

  10. sdut 3-5 学生成绩统计

    3-5 学生成绩统计 Time Limit: 1000MS Memory limit: 65536K 题目描写叙述 通过本题目练习能够掌握对象数组的使用方法,主要是对象数组中数据的输入输出操作. 设计 ...