【算法】在不单调的数组上进行二分查找 力扣162. 寻找峰值

原题链接

文章目录

  • 使用二分查找算法寻找峰值元素
    • 题目描述
    • 示例
    • 提示:
    • 二分查找算法的基本介绍
      • 步骤
      • 代码
      • 复杂度分析
      • 相关资料
    • 算法流程
    • 代码
    • 复杂度分析


使用二分查找算法寻找峰值元素

题目描述

给你一个整数数组 nums,找到一个峰值元素并返回其索引。峰值元素是指其值严格大于左右相邻值的元素。

你可以假设 nums[-1] = nums[n] = -∞

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

示例

示例 1:

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。
示例 2:

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5
解释:你的函数可以返回索引 1,其峰值元素为 2;
     或者返回索引 5, 其峰值元素为 6。

提示:

  • 1 <= nums.length <= 1000
  • -231 <= nums[i] <= 231 - 1
  • 对于所有有效的 i 都有 nums[i] != nums[i + 1]

二分查找算法的基本介绍

一般而言,二分查找算法是一种在有序数组中查找元素的有效算法。它通过将数组分成两半,然后比较目标元素与中间元素来工作。如果目标元素小于中间元素,则它必须在数组的前半部分;如果目标元素大于中间元素,则它必须在数组的后半部分。然后,算法递归地将目标元素所在的部分分成两半,并继续比较,直到找到目标元素或确定它不在数组中。

步骤

  1. 初始化两个指针 leftright,分别指向数组的第一个元素和最后一个元素。
  2. 计算数组的中间元素 mid
  3. 如果 nums[mid] 等于目标元素,则返回 mid
  4. 如果 nums[mid] 小于目标元素,则将 left 指针更新为 mid + 1
  5. 如果 nums[mid] 大于目标元素,则将 right 指针更新为 mid - 1
  6. 重复步骤 2-5,直到 left 指针大于或等于 right 指针。
  7. 如果 left 指针等于 right 指针,并且 nums[left] 等于目标元素,则返回 left
  8. 否则,返回 -1,表示目标元素不在数组中。

代码

def binary_search(nums, target):
    left = 0
    right = len(nums) - 1

    while left <= right:
        mid = (left + right) // 2

        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1

    return -1

复杂度分析

  • 时间复杂度:O(log n),其中 n 是数组 nums 的长度。
  • 空间复杂度:O(1)

相关资料

  • 维基百科上的二分查找算法
  • GeeksforGeeks 上的二分查找算法

算法流程

尽管数组不一定有序,但依然可以使用二分查找算法来解决这个问题,因为二分的思想不一定需要数字上的单调性才能使用,关键在于将问题一分为二

  1. 初始化两个指针 leftright,分别指向数组的第一个元素和最后一个元素。
  2. 计算数组的中间元素 mid
  3. 如果 nums[mid] 大于 nums[mid - 1],则峰值元素在 [mid, right] 中。将 left 指针更新为 mid
  4. 如果 nums[mid] 小于或等于 nums[mid - 1],则峰值元素在 [left, mid - 1] 中。将 right 指针更新为 mid - 1
  5. 重复步骤 2-4,直到 left 指针大于或等于 right 指针。
  6. 返回 left 指针指向的元素的索引。
True
False
True
False
开始
初始化 left 和 right
计算 mid
nums[mid] > nums[mid - 1]
更新 left = mid
left < right
更新right = mid - 1
回到计算mid的代码处
结束循环,返回left指针

代码

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return 0
        left = 0
        right = n - 1
        while left < right:
            mid = (left + right + 1) // 2
            left_ele = nums[mid - 1] if mid - 1 >= 0 else -inf
            right_ele = nums[mid + 1] if mid + 1 < n else -inf
            if nums[mid] > left_ele:
                left = mid
            else:
                right = mid - 1

        return left

复杂度分析

  • 时间复杂度:O(log n),其中 n 是数组 nums 的长度。
  • 空间复杂度:O(1)

你可能感兴趣的:(力扣题目解析,算法,leetcode,数据结构,职场和发展,python,二分查找)