LeetCode 题目 81:搜索旋转排序数组 II

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例
python源码解读
备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。

编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false

输入格式
  • nums:一个可能包含重复元素的整数数组。
  • target:一个整数,表示需要搜索的目标值。
输出格式
  • 返回一个布尔值,表示目标值是否存在于数组中。

示例

示例 1
输入: nums = [2,5,6,0,0,1,2], target = 0
输出: true
示例 2
输入: nums = [2,5,6,0,0,1,2], target = 3
输出: false

方法一:线性搜索

解题步骤
  1. 直接遍历:遍历整个数组,直接比较每个元素是否等于目标值。
完整的规范代码
def search(nums, target):
    """
    线性搜索,直接遍历数组
    :param nums: List[int], 输入的数组
    :param target: int, 需要搜索的目标值
    :return: bool, 目标值是否存在于数组中
    """
    return target in nums

# 示例调用
print(search([2,5,6,0,0,1,2], 0))  # 输出: true
print(search([2,5,6,0,0,1,2], 3))  # 输出: false
算法分析
  • 时间复杂度:(O(n)),在最坏情况下需要遍历整个数组。
  • 空间复杂度:(O(1)),不需要额外的存储空间。

方法二:二分搜索

解题步骤
  1. 二分搜索:尽管数组被旋转过,但仍然可以通过比较中间元素与端点来决定搜索方向。
  2. 处理重复元素:由于存在重复元素,当遇到中间元素等于端点时,不能确定哪部分是有序的,需要逐步缩小范围。
完整的规范代码
def search(nums, target):
    """
    二分搜索在可能存在重复元素的旋转排序数组中查找目标值
    :param nums: List[int], 输入的数组
    :param target: int, 需要搜索的目标值
    :return: bool, 目标值是否存在于数组中
    """
    if not nums:
        return False

    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] == target:
            return True
        
        if nums[left] == nums[mid] == nums[right]:
            left += 1
            right -= 1
        elif nums[left] <= nums[mid]:
            if nums[left] <= target < nums[mid]:
                right = mid - 1
            else:
                left = mid + 1
        else:
            if nums[mid] < target <= nums[right]:
                left = mid + 1
            else:
                right = mid - 1
    return False

# 示例调用
print(search([2,5,6,0,0,1,2], 0))  # 输出: true
print(search([2,5,6,0,0,1,2], 3))  # 输出: false
算法分析
  • 时间复杂度:平均情况 (O(\log n)),但在最坏情况下由于重复元素的存在可能退化到 (O(n))。
  • 空间复杂度:(O(1)),使用常数空间进行计算。

方法三:修改的二分搜索

解题步骤
  1. 优化二分搜索:对二分搜索进行修改,处理数组中的重复元素和旋转的情况。
  2. 区间收缩:当无法确定哪部分有序时,适当缩小搜索区间。
完整的规范代码
def search(nums, target):
    """
    修改的二分搜索,优化处理旋转数组和重复元素
    :param nums: List[int], 输入的数组
    :param target: int, 需要搜索的目标值
    :return: bool, 目标值是否存在于数组中
    """
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] == target:
            return True
        # 判断哪一半是有序的
        if nums[left] < nums[mid]:  # 左半部分有序
            if nums[left] <= target < nums[mid]:
                right = mid - 1
            else:
                left = mid + 1
        elif nums[left] > nums[mid]:  # 右半部分有序
            if nums[mid] < target <= nums[right]:
                left = mid + 1
            else:
                right = mid - 1
        else:  # 无法判断哪半部分有序
            left += 1
    return False

# 示例调用
print(search([2,5,6,0,0,1,2], 0))  # 输出: true
print(search([2,5,6,0,0,1,2], 3))  # 输出: false
算法分析
  • 时间复杂度:在无重复元素的情况下为 (O(\log n)),但当存在大量重复元素时可能接近 (O(n))。
  • 空间复杂度:(O(1)),只使用了有限的额外空间。

方法四:哈希表

解题步骤
  1. 使用哈希表:将所有元素存储在哈希表中,然后检查目标值是否存在于哈希表中。
完整的规范代码
def search(nums, target):
    """
    使用哈希表检查目标值是否存在于数组中
    :param nums: List[int], 输入的数组
    :param target: int, 需要搜索的目标值
    :return: bool, 目标值是否存在于数组中
    """
    return target in set(nums)

# 示例调用
print(search([2,5,6,0,0,1,2], 0))  # 输出: true
print(search([2,5,6,0,0,1,2], 3))  # 输出: false
算法分析
  • 时间复杂度:(O(n)),建立哈希表需要 (O(n)) 时间。
  • 空间复杂度:(O(n)),存储所有元素需要 (O(n)) 空间。

方法五:递归分治

解题步骤
  1. 递归分治:将数组分为两部分,分别搜索,递归处理每部分。
  2. 处理重复和旋转:在递归过程中处理重复元素和数组的旋转状态。
完整的规范代码
def search(nums, target):
    """
    使用递归分治法搜索旋转排序数组
    :param nums: List[int], 输入的数组
    :param target: int, 需要搜索的目标值
    :return: bool, 目标值是否存在于数组中
    """
    def helper(l, r):
        if l > r:
            return False
        mid = (l + r) // 2
        if nums[mid] == target:
            return True
        # 分治递归
        return helper(l, mid - 1) or helper(mid + 1, r)
    
    return helper(0, len(nums) - 1)

# 示例调用
print(search([2,5,6,0,0,1,2], 0))  # 输出: true
print(search([2,5,6,0,0,1,2], 3))  # 输出: false
算法分析
  • 时间复杂度:(O(n)),在最坏情况下可能需要搜索整个数组。
  • 空间复杂度:(O(\log n)),递归栈的深度依赖于数组长度。

不同算法的优劣势对比

特征方法一:线性搜索方法二:二分搜索方法三:修改的二分搜索方法四:哈希表方法五:递归分治
时间复杂度(O(n))(O(\log n)) ~ (O(n))(O(\log n)) ~ (O(n))(O(n))(O(n))
空间复杂度(O(1))(O(1))(O(1))(O(n))
优势简单直观,适用于所有情况在没有重复元素的情况下非常高效可以有效处理重复元素和旋转快速查找,适用于大数据利用递归处理复杂的重复和旋转问题
劣势效率较低,尤其是在数组较长时在重复元素多的情况下性能下降较复杂,需要处理多种边界情况需要额外的存储空间可能造成栈溢出,效率不稳定

应用示例

搜索算法通常用于

  • 数据库查询:特别是在处理包含大量重复元素的数据集时,有效的搜索算法可以极大地提高查询效率。
  • 实时系统:在需要快速响应的系统中,高效的搜索算法可以减少延迟,提高用户满意度。
  • 数据分析:在数据科学中,经常需要在大规模数据集中寻找特定的模式或信息,优化的搜索算法在这种场景下尤为重要。

每种方法都有其适用场景,选择合适的算法依赖于具体的应用需求、数据的特性以及性能的要求。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数据分析螺丝钉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值