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

简介: 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))
优势 简单直观,适用于所有情况 在没有重复元素的情况下非常高效 可以有效处理重复元素和旋转 快速查找,适用于大数据 利用递归处理复杂的重复和旋转问题
劣势 效率较低,尤其是在数组较长时 在重复元素多的情况下性能下降 较复杂,需要处理多种边界情况 需要额外的存储空间 可能造成栈溢出,效率不稳定

应用示例

搜索算法通常用于

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

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


欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
1月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
1月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
19 4
|
1月前
|
算法 索引
LeetCode(搜索插入位置)
如何使用二分查找算法来解决LeetCode上的“搜索插入位置”问题,确保时间复杂度为O(log n),并提供了详细的代码实现和分析。
14 2
|
1月前
|
机器学习/深度学习
Leetcode第48题(旋转图像)
这篇文章介绍了LeetCode第48题“旋转图像”的解题方法,通过原地修改二维矩阵实现图像的顺时针旋转90度。
27 0
Leetcode第48题(旋转图像)
|
1月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
18 0
Leetcode第三十三题(搜索旋转排序数组)
|
1月前
【LeetCode 39】700.二叉搜索树中的搜索
【LeetCode 39】700.二叉搜索树中的搜索
14 0
|
1月前
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
56 0
|
1月前
|
C++
【LeetCode 12】349.两个数组的交集
【LeetCode 12】349.两个数组的交集
16 0
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
113 2