魔术索引
题目
魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。
注:可以有重复数字
思路
最简单的思路是一次遍历,从左开始找到最小的i使得i=A[i]。但这并不是本体考察的重点,在没有重复数字的情况下,本题是可以使用二分查找来做的:
- 当A[i]=i时,做小的满足A[i]=i的索引只有可能出现在0,…,i-1,我们只需记录这个i然后在从左侧搜索。
- 当A[i]>i时,i的右侧必不可能出现A[i]=i,我们只需从左侧进行搜素。
- 当A[i]<i时,i的左侧必不可能出现A[i]=i,我们只需从右侧进行搜索。
然而该题允许重复数字出现,也就是说无法通过A[i]>i,A[i]<i来判断搜索区间,只能进行适当的剪枝。
- 当A[i]=i时,做小的满足A[i]=i的索引只有可能出现在0,…,i-1,我们只需记录这个i然后在从左侧搜索。
- 当A[i]>i或A[i]<i时,两侧都需要进行搜索,我们先搜索左侧,若有A[i]=i则返回,不必再搜索右侧;若没有,继续搜索右侧。
class Solution {
public int min = -1;
public int findMagicIndex(int[] nums) {
if(nums == null || nums.length == 0){
return -1;
}
recur(nums, 0, nums.length-1);
return min;
}
public boolean recur(int[] nums, int left, int right){
int mid = left + (right-left) / 2;
if(left == right){
if(nums[left] == left){
if(min == -1){
min = left;
}else{
min = Math.min(min, left);
}
return true;
}
return false;
}
else if(nums[mid] == mid){
if(min == -1){
min = mid;
}else{
min = Math.min(min, mid);
}
recur(nums, left, mid);
return true;
}
return recur(nums, left, mid) || recur(nums, mid+1, right);
}
}