【刷题之路】LeetCode 程序员面试金典 08.03. 魔术索引

一、题目描述

原题连接: 面试题 08.03. Magic Index LCCI
题目描述:
魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。

示例1:

输入: nums = [0, 2, 3, 4, 5]
输出: 0
说明: 0下标的元素为0

示例2:

输入: nums = [1, 1, 1]
输出: 1

说明:
nums长度在[1, 1000000]之间
此题为原书中的 Follow-up,即数组中可能包含重复元素的版本

二、解题

1、方法1——暴力法

1.1、思路分析

最简单的方法就是直接遍历数组的每个元素,找到第一个nums[i] = i的元素,直接返回其下标即可。

1.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

int findMagicIndex1(int* nums, int numsSize) {
    assert(nums);
    int i = 0;
    for (i = 0; i < numsSize; i++) {
        if (nums[i] == i) {
            return i;
        }
    }
    return -1;
}

时间复杂度:O(n),n为数组长度,最坏情况下我们需要遍历完数组中的所有元素。
空间复杂度:O(1),我们只需要用到常数级的额外空间。

2、方法2——二分+分治

2.1、思路分析

既然是在有序数组中进行查找,那我们很容易就能想到能使用二分查找,具体算法思路如下:
如果nums[mid] == mid,则说明如果想要找到更优解,就只能继续mid的左侧:
在这里插入图片描述
而当nums[mid] != mid时,并不能确定最优解是在左侧还是在右侧,因为左侧和右侧都有可能存在符合条件的解或者不存在解。所以我们这时候左侧右侧的区间都要寻找一遍:
在这里插入图片描述
所以在二分的基础上我们还需要使用分治算法的思想,来递归寻找左右两侧区间,只不过这里我们得有先寻找左侧区间,
如果在左区间找到了更优解,那就不需要再寻找右区间了。

2.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

// 先写一个二分分治算法
void binary_finder(int* nums, int left, int right, int* answer) {
    assert(nums && answer);
    if (left < right) { // 递归结束条件
        return;
    }
    int mid = left + (right - left) / 2;
    if (nums[mid] == mid) {
        *answer = mid;
        return binary_finder(nums, left, mid - 1, answer);
    }
    else {
        return binary_finder(nums, left, mid - 1, answer);
        if (-1 == *answer || *answer > right) {
            return binary_finder(nums, mid + 1, right, answer);
        }
    }
}
int findMagicIndex2(int* nums, int numsSize) {
    assert(nums);
    int answer = -1;
    binary_finder(nums, 0, numsSize - 1, &answer);
    return answer;
}
int main() {
    int nums[] = { 3,4,5,5,5,5 };
    int len = sizeof(nums) / sizeof(nums[0]);
    int result = findMagicIndex2(nums, len);
    printf("%d\n", result);
    return 0;
}

时间复杂度:O(n),n为数组的长度,最坏情况下,我们还是需要遍历完数组中的所有元素。
空间复杂度:O(n),空间复杂度主要取决于递归调用的次数,最坏的情况下我们每个元素都要判断一次,故需要调用n次,空间复杂度为O(n)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林先生-1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值