LeetCode《程序员面试金典》面试题 08.03. 魔术索引

题目

在这里插入图片描述
注意点:

  1. 有序整数数组
  2. 可能存在多个魔术索引
  3. 数组可能包含重复元素

解题

解题一:线性搜索 + 剪枝

在这里插入图片描述
不过,既然给定数组是有序的,我们理应充分利用这个条件。

// javascript
var findMagicIndex = function(nums) {
    for (let i = 0; i < nums.length; i = Math.max(i + 1, nums[i])) {
        if (i === nums[i]) return i;
    }
    return -1;
};

时间复杂度:最坏情况下会达到 O ( n ) O(n) O(n) 的时间复杂度,其中 n n n 为数组的长度。
空间复杂度: O ( 1 ) O(1) O(1)

解题二:二分查找 + 剪枝

下面解法适用于:至多有一个魔术索引 & 数组不包含重复元素
在这里插入图片描述
下面解法适用于:至多有一个魔术索引 & 数组可能包含重复元素
在这里插入图片描述
在这里插入图片描述
上面的代码先比较中间元素,再去左半部分搜索,然后去右半部分搜索。假设数组为 [-99, -87, -69, -51, -40, -38, -31, -30, -18, -1, 10, 11, 41, 63, 71, 72, 72, 78, 86, 88],找到的是 index 11, value 11,找到 11 后没有再去找 index 10,导致找到的不是最小魔术索引,因而需要改变一下判断顺序,即:如果左边没有找到魔术索引,再比较中间元素

// javascript
var findMagicIndex = function(nums) {
    return magicFast(nums, 0, nums.length - 1);
};

var magicFast = function(nums, start, end) {
    if (start > end) return -1;
    // 搜索左半部分
    let midIndex = Math.floor((start + end) / 2),
        midValue = nums[midIndex];
    let leftIndex = Math.min(midIndex - 1, midValue);
    let left = magicFast(nums, start, leftIndex);
    if (left >= 0) return left;
    // 比较中间元素
    if (midIndex === midValue) return midIndex;
    // 搜索右半部分
    let rightIndex = Math.max(midIndex + 1, midValue);
    let right = magicFast(nums, rightIndex, end);
    return right;
};

时间复杂度:最坏情况下会达到 O ( n ) O(n) O(n) 的时间复杂度,其中 n n n 为数组的长度;最好情况下 O ( l o g n ) O(logn) O(logn)
空间复杂度:递归函数的空间取决于调用的栈深度,而最坏情况下我们会递归 n n n 层,即栈深度为 O ( n ) O(n) O(n)

官方解答:魔术索引

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值