Leetcode 162 寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

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

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

目录

常见排序算法的时间复杂度

1. 线性查找(顺序查找)

2. 二分查找

3. 二叉搜索树查找

4. 平衡二叉搜索树查找(如AVL树、红黑树)

5. 哈希查找

6. 跳表查找

7. 斐波那契查找

 解题关键及代码

 二分法的一些关键点

1.整数溢出

2.边界问题


常见排序算法的时间复杂度

1. 线性查找(顺序查找)

  • 时间复杂度: O(n)
  • 描述: 线性查找通过遍历数组或列表中的每个元素,逐一检查是否与目标值匹配。它不需要数据预先排序。

2. 二分查找

  • 时间复杂度: O(log n)
  • 描述: 二分查找适用于已排序的数组,每次将查找范围缩小一半,直到找到目标值或查找范围为空。

3. 二叉搜索树查找

  • 时间复杂度:
    • 平均情况: O(log n)
    • 最坏情况: O(n)(当树退化为链表时)
  • 描述: 在二叉搜索树中查找元素,每一步可以排除一半的可能性,但如果树不平衡,效率会下降。

4. 平衡二叉搜索树查找(如AVL树、红黑树)

  • 时间复杂度: O(log n)
  • 描述: 平衡二叉搜索树通过维持树的平衡,确保查找、插入和删除操作的最坏情况时间复杂度都是 O(log n)。

5. 哈希查找

  • 时间复杂度:
    • 平均情况: O(1)
    • 最坏情况: O(n)(当哈希冲突导致很多元素映射到同一个哈希桶时)
  • 描述: 通过哈希表进行查找,元素通过哈希函数映射到一个桶中。理想情况下可以直接定位到元素,但需要处理哈希冲突。

6. 跳表查找

  • 时间复杂度: O(log n)
  • 描述: 跳表是对链表的一种改进,通过增加多级索引来提高查找效率。适用于元素有序的情况。

7. 斐波那契查找

  • 时间复杂度: O(log n)
  • 描述: 斐波那契查找是二分查找的一种变体,使用斐波那契数列来分割数组,适用于已排序的数组。

     

 解题关键及代码

根据时间复杂度的提示,可以考虑二分查找的方法,本题的解题重点在于:在题目描述中出现了 nums[-1] = nums[n] = -∞,这就代表着 只要数组中存在一个元素比相邻元素大,那么沿着它一定可以找到一个峰值。

class Solution {
    public int findPeakElement(int[] nums) {
        int left = 0, right = nums.length - 1;
        for (; left < right; ) {
            int mid = left + (right - left) //注意点1:整数溢出
            if (nums[mid] > nums[mid + 1]) {
                right = mid;
            } else {
                left = mid + 1;//注意点2:注意边界的修改,防止无限循环超时
            }
        }
        return left;
    }
}

 二分法的一些关键点

1.整数溢出

取中点时:left + (right - left) / 2,这是因为

在计算机中,整数的存储是有限的。例如,在Java中,int 类型是32位的,能够表示的数值范围是从 -2^312^31 - 1(即-2,147,483,648到2,147,483,647)。如果进行的计算超出了这个范围,就会发生溢出,意味着计算结果会不正确地“回绕”到整数的另一端。

直接计算中点可能导致的溢出

当你直接使用 (left + right) / 2 来计算中点时,如果 leftright 都非常大(接近int类型的最大值),它们的和可能会超出 int 能够表示的最大值,导致溢出。这种情况下,计算的中点值将是不正确的。

使用 left + (right - left) / 2 避免溢出

这个方法通过首先计算 rightleft 的差值,然后将这个差值除以2,最后将结果加到 left 上,来计算中点。这种方式的关键在于:

  • right - left 不会超过 int 类型的最大值(因为即使在最极端的情况下,left 是0,right2^31 - 1,它们的差值也是在 int 的表示范围内)。
  • 由于 left(right - left) / 2 的和不会超过 int 的最大值,这种方式避免了溢出的风险。
     

2.边界问题(第一次做right边界没改超时了555)
 

  • 更新 right: 如果 nums[mid] 大于 nums[mid + 1],这表明目标元素可能在当前中点的左侧(包括中点自身),因为你已经找到了一个递减的序列。因此,你将 right 更新为 mid,来缩小搜索区间到左半部分。
     

  • 更新 left: 如果 nums[mid] 不大于 nums[mid + 1](即 else 分支),这意味着目标元素位于中点的右侧,因为你处于一个递增的序列。这时,你需要将 left 更新为 mid + 1,排除中点和它左侧的所有元素,将搜索范围缩小到右半部分。这里 mid + 1 是因为你已经确定 mid 不是目标,所以从 mid 的下一个元素开始搜索。

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值