LeetCode 算法:搜索旋转排序数组 c++

原题链接🔗搜索旋转排序数组
难度:中等⭐️⭐️

题目

整数数组 nums 按升序排列,数组中的值 互不相同

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。

例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例 2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例 3:

输入:nums = [1], target = 0
输出:-1

提示:

  • 1 <= nums.length <= 5000
  • -104 <= nums[i] <= 104
  • nums 中的每个值都 独一无二
  • 题目数据保证 nums 在预先未知的某个下标上进行了旋转
  • -104 <= target <= 104

二分查找

  1. 二分查找(Binary Search),也称为折半搜索,是一种在有序数组中查找特定元素的搜索算法。其基本思想是将目标值与数组中间的元素进行比较:

    1. 如果目标值等于中间元素,搜索成功,返回该位置。
    2. 如果目标值小于中间元素,搜索范围缩小至数组的左半部分。
    3. 如果目标值大于中间元素,搜索范围缩小至数组的右半部分。
    4. 这个过程将不断重复,直到找到目标值或者搜索范围为空为止。
  2. 以下是二分查找算法的一般步骤:

    1. 初始化:设置两个指针,一个指向数组的起始位置(通常记为 left),另一个指向数组的结束位置(通常记为 right)。

    2. 循环条件:当 left 小于等于 right 时,继续循环。

    3. 计算中间位置:计算 leftright 之间的中间位置 mid,通常使用 (left + right) / 2

    4. 比较与调整

      • 如果 nums[mid] 等于目标值,根据需要返回 mid 或继续搜索以找到更精确的位置。
      • 如果 nums[mid] 大于目标值,将 right 调整为 mid - 1
      • 如果 nums[mid] 小于目标值,将 left 调整为 mid + 1
    5. 循环结束:如果 left 大于 right,则表示目标值不在数组中,返回一个特定的值(通常是 -1)表示未找到。

  3. 二分查找的效率非常高,时间复杂度为 O(log n),其中 n 是数组的长度。然而,它要求数组是有序的,并且只能应用于一维有序数组。

  4. 下面是一个简单的 C++ 实现示例:

int binarySearch(const std::vector<int>& nums, int target) {
    int left = 0, right = nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2; // 防止溢出
        if (nums[mid] == target) {
            return mid; // 找到目标值
        } else if (nums[mid] < target) {
            left = mid + 1; // 搜索右半部分
        } else {
            right = mid - 1; // 搜索左半部分
        }
    }
    return -1; // 未找到目标值
}

这个函数会返回目标值在数组中的索引,如果目标值不在数组中,则返回 -1。

题解

  1. 解题思路:
  • 确定二分查找的可行性:由于数组是局部有序的,我们可以使用二分查找算法来减少搜索范围。

  • 确定中间元素和边界元素的比较:在二分查找的过程中,我们需要比较中间元素与边界元素,以确定应该在左半部分还是右半部分继续搜索。

  • 处理旋转点:由于数组被旋转,我们需要找到旋转点,即数组中第一个大于或等于中间元素的索引。

  • 二分查找逻辑:

    • 如果中间元素等于目标值,返回中间索引。
    • 如果左边界元素小于或等于中间元素(即左边是有序的),比较目标值与左边界和中间元素:
      • 如果目标值在左边界和中间元素之间,搜索左半部分。
      • 否则,搜索右半部分。
    • 否则(即右边是有序的),比较目标值与中间元素和右边界:
      • 如果目标值在中间元素和右边界之间,搜索右半部分。
      • 否则,搜索左半部分。
  • 更新搜索范围:根据上述逻辑,更新左右边界,继续二分查找,直到找到目标值或搜索范围无效。

  • 返回结果:如果找到目标值,返回其索引;否则,返回-1。

  1. c++ demo:
#include <iostream>
#include <vector>

// 函数声明
int search(const std::vector<int>& nums, int target);

int main() {
    // 测试用例
    std::vector<int> nums1 = { 4, 5, 6, 7, 0, 1, 2 };
    int target1 = 0;
    std::cout << "Test 1 - Expected: 4, Found: " << search(nums1, target1) << std::endl;

    std::vector<int> nums2 = { 4, 5, 6, 7, 0, 1, 2 };
    int target2 = 3; // 注意,这里的目标值不在数组中
    std::cout << "Test 2 - Expected: -1, Found: " << search(nums2, target2) << std::endl;

    return 0;
}

// 函数定义
int search(const std::vector<int>& nums, int target) {
    int left = 0, right = nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            return mid;
        }
        // 判断左侧是否有序
        if (nums[left] <= nums[mid]) {
            if (nums[left] <= target && target < nums[mid]) {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
        else { // 右侧有序
            if (nums[mid] < target && target <= nums[right]) {
                left = mid + 1;
            }
            else {
                right = mid - 1;
            }
        }
    }
    return -1; // 如果没有找到目标值,返回-1
}
  • 输出结果:

Test 1 - Expected: 4, Found: 4
Test 2 - Expected: -1, Found: -1

  1. 代码仓库地址search
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码流怪侠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值