leetcode
leetcode 1701 ~ 1750
寻找峰值 II

寻找峰值 II

难度:

标签:

题目描述

一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。

给你一个 从 0 开始编号 m x n 矩阵 mat ,其中任意两个相邻格子的值都 不相同 。找出 任意一个 峰值 mat[i][j]返回其位置 [i,j]

你可以假设整个矩阵周边环绕着一圈值为 -1 的格子。

要求必须写出时间复杂度为 O(m log(n))O(n log(m)) 的算法

 

 

示例 1:

输入: mat = [[1,4],[3,2]]
输出: [0,1]
解释: 3 和 4 都是峰值,所以[1,0]和[0,1]都是可接受的答案。

示例 2:

输入: mat = [[10,20,15],[21,30,14],[7,16,32]]
输出: [1,1]
解释: 30 和 32 都是峰值,所以[1,1]和[2,2]都是可接受的答案。

 

提示:

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n <= 500
  • 1 <= mat[i][j] <= 105
  • 任意两个相邻元素均不相等.

代码结果

运行时间: 36 ms, 内存: 43.8 MB


// 使用Java Stream无法直接实现该算法,因为它需要在数组中执行二分查找和条件检查。
// 但我们可以用Java流来简化某些操作,比如查找最大值所在的行。
// 思路与上述Java解法类似。

import java.util.stream.IntStream;

public class Solution {
    public int[] findPeakGrid(int[][] mat) {
        int m = mat.length;
        int n = mat[0].length;
        int left = 0, right = n - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            int maxRow = IntStream.range(0, m)
                                   .boxed()
                                   .max((i, j) -> Integer.compare(mat[i][mid], mat[j][mid]))
                                   .get();
            boolean isPeak = true;
            if (mid > 0 && mat[maxRow][mid] < mat[maxRow][mid - 1]) {
                right = mid - 1;
                isPeak = false;
            }
            if (mid < n - 1 && mat[maxRow][mid] < mat[maxRow][mid + 1]) {
                left = mid + 1;
                isPeak = false;
            }
            if (isPeak) {
                return new int[]{maxRow, mid};
            }
        }
        return new int[]{-1, -1}; // 不会执行到这里
    }
}

解释

方法:

该题解采用了二分搜索的策略,但不同于常规的一维二分搜索,它是对二维矩阵的行进行二分搜索。首先,选定中间行,然后在该行中找到最大值的列索引。接着,比较这个元素与其上下元素的大小。如果它小于上面的元素,则峰值在上半部分,调整高指针;如果它小于下面的元素,则峰值在下半部分,调整低指针。如果当前元素是当前所在列的最大值,并且比相邻的上下行元素都要大,则它就是一个峰值,返回其位置。

时间复杂度:

O(n log(m))

空间复杂度:

O(1)

代码细节讲解

🦆
在二分搜索中,选定中间行后,为什么总是选择该行中的最大值的列索引进行下一步比较?
在二维矩阵中,选定中间行后选择该行中的最大值的列索引进行下一步比较是因为这个最大值有可能是一个局部峰值。从这个最大值出发,只需要比较其上下的元素即可快速确定是否存在更高的值,从而决定搜索的方向。这种方法有效减少了比较的范围和复杂度,使得算法更加高效。
🦆
如果中间行的最大值同样是列中的最高点,但其相邻格子有相同的值(不考虑题目中假设的不相同情况),这种搜索方法还有效吗?
在题目假设中,矩阵的所有元素都是不相同的,这使得每次比较都能明确地决定搜索方向。如果假设不成立,即存在相同的值,则可能无法通过当前的比较确定明确的搜索方向,因为可能存在多个相同的局部最大值。在这种情况下,算法可能需要更多的逻辑来处理这种特殊情况,或者可能无法保证总是找到峰值。
🦆
题解中提到的边界检查,如`i - 1 >= 0`和`i + 1 < m`,是如何确保不会越界访问矩阵的?
这些边界检查确保在比较当前元素与其上下行元素时,不会访问矩阵的外部。`i - 1 >= 0` 确保当前行不是第一行,从而可以安全地访问上一行;`i + 1 < m` 确保当前行不是最后一行,从而可以安全地访问下一行。这些检查是防止数组越界异常的重要保护措施。
🦆
题解假设整个矩阵周边环绕着一圈值为`-1`的格子,这种假设在实际代码实现中如何体现?
题解中的这种假设主要是为了简化边界条件的处理。在实际代码实现中,我们并没有真正添加这样一圈值为`-1`的格子,而是通过边界检查(如前述的`i - 1 >= 0`和`i + 1 < m`)来模拟这种情况。这样,任何尝试访问矩阵边界之外的元素的操作都会被这些边界检查所阻止,从而在逻辑上等同于周边有`-1`的格子。

相关问题