面试基础---面试刷题推荐 二分查找算法:搜索旋转排序数组

二分查找算法:搜索旋转排序数组

引言:二分查找的核心思想

二分查找是一种高效的搜索算法,适用于有序数组。它的核心思想是通过不断缩小搜索范围,将时间复杂度从 O(n) 降低到 O(log n)。本文将以“搜索旋转排序数组”为例,详细讲解二分查找的实现,并提供易于记忆的代码模板。


一、问题描述

1.1 题目

假设一个按升序排列的数组在某个未知的点上进行了旋转(例如,[0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2])。给定一个目标值 target,如果在数组中找到它,则返回其索引,否则返回 -1

示例

  • 输入:nums = [4,5,6,7,0,1,2], target = 0
  • 输出:4
  • 解释:0 在数组中的索引为 4

二、二分查找算法思路

2.1 核心思想

  • 旋转数组特性:旋转后的数组可以分为两个有序的子数组。
  • 二分查找
    • 通过比较中间元素与目标值,确定目标值位于哪个有序子数组。
    • 根据目标值与有序子数组的关系,调整搜索范围。

2.2 算法步骤

  1. 初始化左右边界 leftright
  2. left <= right 的条件下,进行二分查找:
    • 计算中间索引 mid
    • 如果 nums[mid] 等于 target,返回 mid
    • 判断 nums[mid] 是否位于左半部分有序数组:
      • 如果是,判断 target 是否在左半部分,调整搜索范围。
      • 如果不是,判断 target 是否在右半部分,调整搜索范围。
  3. 如果未找到 target,返回 -1

三、代码实现

3.1 Java 实现

public int search(int[] nums, int target) {
    int left = 0, right = nums.length - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;

        if (nums[mid] == target) {
            return mid;
        }

        // 判断 mid 是否位于左半部分有序数组
        if (nums[mid] >= nums[left]) {
            // 判断 target 是否在左半部分
            if (target >= nums[left] && target < nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        } else {
            // 判断 target 是否在右半部分
            if (target > nums[mid] && target <= nums[right]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    }

    return -1;
}

3.2 代码讲解

  1. 初始化

    • left:搜索范围的左边界,初始为 0。
    • right:搜索范围的右边界,初始为 nums.length - 1
  2. 二分查找

    • 计算中间索引 mid
    • 如果 nums[mid] 等于 target,直接返回 mid
    • 判断 nums[mid] 是否位于左半部分有序数组:
      • 如果是,判断 target 是否在左半部分,调整搜索范围。
      • 如果不是,判断 target 是否在右半部分,调整搜索范围。
  3. 返回结果

    • 如果未找到 target,返回 -1

四、易于记忆的代码模板

4.1 二分查找通用模板

public int binarySearchTemplate(int[] nums, int target) {
    int left = 0, right = nums.length - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;

        if (nums[mid] == target) {
            return mid;
        }

        if (nums[mid] >= nums[left]) {
            if (target >= nums[left] && target < nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        } else {
            if (target > nums[mid] && target <= nums[right]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    }

    return -1;
}

4.2 模板解析

  • 初始化leftright
  • 二分查找:计算 mid,判断 nums[mid]target 的关系,调整搜索范围。
  • 返回结果:找到 target 返回索引,否则返回 -1

五、复杂度分析

5.1 时间复杂度

  • 最坏情况:每次将搜索范围缩小一半,时间复杂度为 O(log n),其中 n 是数组长度。

5.2 空间复杂度

  • 最坏情况:只使用了常数级别的额外空间,空间复杂度为 O(1)

六、总结

二分查找算法是解决有序数组搜索问题的利器,通过不断缩小搜索范围,可以高效地找到目标值。对于“搜索旋转排序数组”问题,二分查找算法的时间复杂度为 O(log n),空间复杂度为 O(1),是一种非常高效的解决方案。

通过掌握二分查找的通用模板,可以轻松应对类似的搜索问题。希望本文的讲解和代码实现能帮助大家更好地理解和记忆二分查找算法!

你可能感兴趣的:(leetcode刷题,算法,面试,数据结构,架构,分布式,职场和发展,java)