天天看点

魔术索引算法

题目介绍

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

蛮力法

遍历整个数组,遇到符合条件的元素,返回索引。若没有符合条件的元素,返回-1。

魔术索引算法

蛮力法实现:

public static int magicBruteForce(int[] arr){
    for (int i = 0; i < arr.length; i++) {
        if(arr[i] == i) return i;
    }
    return -1;
}           

时间复杂度:O(n)。

二分查找法

因为数组是有序的,我们可以用二分查找法,将时间复杂度降到O(lgn)。

二分查找法: 通过不断将要搜素的间隔分裂成一半,来搜索一个已经排好序的数组。首先,一个间隔覆盖整个数组。如果搜索键的值小于间隔中间的项,将搜索区间缩小一半(留值小的一半)。否则将搜索区间缩小一半(留值大的一半)。反复检查间隔,直到找到要找的值或者间隔已经是空的。

step1:

mid = 5, A[mid] = 12;

A[mid] > mid;

留左半边数组;

魔术索引算法

step2:

mid = 2, A[mid] = 1;

A[mid] < mid;

留右半边数组;

魔术索引算法

step3:

mid = 3, A[mid] = 3;

A[mid] == mid;

返回索引mid;

魔术索引算法

二分查找法实现:

public static int magicBinary(int[] arr){
    return magicBinary(0, arr.length-1, arr);
}

private static int magicBinary(int low, int high, int[] arr){
    if(low > high) return -1;
    int mid = (low + high)/2;
    if(arr[mid] == mid) return mid;
    else if(arr[mid] > mid) return magicBinary(low, mid - 1, arr);
    else return magicBinary(mid + 1, high, arr);
}           

时间复杂度:O(lgn)。

进阶:如果数组元素有重复值

魔术索引算法

观察上图,我们可以看到当有重复值时,A[mid] < mid时,搜索右半边不再成立。此时魔术索引可以在数组右侧(A[1]),也可以在左侧(A[8])。

根据上图的例子,那是不是说魔术索引可以在左边或右边的任意位置?当然不是!

其实,我们可以看到A[5] = 3 时,魔术索引只可能存在于A[0]到A[3]之间。因此,我们在搜索时可以跳过一些元素。

综上所述,有重复值时我们的搜索逻辑为:

  1. A[mid] == mid, 返回索引mid, 结束搜索;
  2. 搜索左半部分:low不变,high = min(mid-1, A[mid])
  3. 搜索右半部分:high不变,low = max(mid+1, A[mid])

代码实现:

public static int magicBinaryDup(int[] arr){
    return magicBinaryDup(0, arr.length-1, arr);
}

private static int magicBinaryDup(int low, int high, int[] arr){
    if(low > high) return -1;
    int mid = (low + high)/2;
    if(arr[mid] == mid) return mid;

    //left part
    int highLeft = Math.min(mid - 1, arr[mid]);
    int leftResult =  magicBinaryDup(low, highLeft, arr);
    if(leftResult > 0) return leftResult;
    
    //right part
    int lowRight = Math.max(mid + 1, arr[mid]);
    int rightResult = magicBinaryDup(lowRight, high, arr);
    return rightResult;
}           

继续阅读