寻找峰值Ⅱ(LeetCode日记)

LeetCode-1901-寻找峰值Ⅱ

题目信息:

一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。
给你一个 从 0 开始编号 的 m x n m x n mxn 矩阵 m a t mat mat ,其中任意两个相邻格子的值都 不相同 。找出 任意一个 峰值 m a t [ i ] [ j ] mat[i][j] mat[i][j] 并 返回其位置 [ i , j ] [i,j] [i,j]
你可以假设整个矩阵周边环绕着一圈值为 -1 的格子。
要求必须写出时间复杂度为 O ( m l o g ( n ) ) O(m log(n)) O(mlog(n)) O ( n l o g ( m ) ) O(n log(m)) O(nlog(m)) 的算法
寻找峰值Ⅱ(LeetCode日记)_第1张图片
寻找峰值Ⅱ(LeetCode日记)_第2张图片

提示:

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

题解

方法:二分法;
m m m n n n 分别为 m a t mat mat 的行数和列数。首先对于一维数组,因为任意两个相邻的格子的值都不相同,所以它的最大值必定是该一维数组的峰值。基于这一点,我们可以只考虑每一行的最大值,记第 i i i 行的最大值为第 j i j_i ji列元素,如果 m a t [ i ] [ j i ] > m a t [ i − 1 ] [ j i ] mat[i][j_i]>mat[i−1][j_i] mat[i][ji]>mat[i1][ji] m a t [ i ] [ j i ] > m a t [ i + 1 ] [ j i ] mat[i][j_i]>mat[i+1][j_i] mat[i][ji]>mat[i+1][ji](对于数组越界的情况,取 − 1 −1 1 值),那么 ( i , j i ) (i,j_i) (i,ji)即为结果。
对于题目给定的条件,是否一定存在峰值呢?答案是肯定的。证明可以采用反证法:

如果不存在峰值,根据题目给定的条件,我们知道第0 行的最大值比它上面的格子(值为 −1)大,那么初始时有 i = 0 i=0 i=0 行的最大值满足比上面格子大的条件。如果第 i i i行的最大值满足比它上面的格子大这一条件,那么根据不存在峰值的前提,我们有 m a t [ i ] [ j i ] < m a t [ i + 1 ] [ j i ] mat[i][ji]mat[i][ji]<mat[i+1][ji],而 m a t [ i + 1 ] [ j i + 1 ] ≥ m a t [ i + 1 ] [ j i ] > m a t [ i ] [ j i ] ≥ m a t [ i ] [ j i + 1 ] mat[i+1][j_i+1]≥mat[i+1][j_i]>mat[i][j_i]≥mat[i][j_{i+1}] mat[i+1][ji+1]mat[i+1][ji]>mat[i][ji]mat[i][ji+1],从而我们有 m a t [ i + 1 ] [ j i + 1 ] > m a t [ i ] [ j i + 1 ] mat[i+1][j_i+1]>mat[i][j_{i+1}] mat[i+1][ji+1]>mat[i][ji+1],即 i + 1 i+1 i+1也满足条件。基于以上推导,使用数学归纳法,当 i = m − 1 i=m−1 i=m1时,有 m a t [ m − 1 ] [ j m − 1 ] > m a t [ m − 2 ] [ j m − 1 ] mat[m−1][j_{m−1}]>mat[m−2][j_{m−1}] mat[m1][jm1]>mat[m2][jm1],而下面的格子值为 − 1 -1 1,显然 ( m − 1 , j m − 1 ) (m−1,j_{m−1}) (m1,jm1) 为峰值,与不存在峰值矛盾。

根据以上证明,我们也可以得出这样一个结论,即如果 i 1 i_1 i1行的最大值比它上面的格子大, i 2 i_2 i2行比它下面的格子大,且 i 1 ≤ i 2 i_1 \leq i_2 i1i2 ,那么 [ i 1 , i 2 ] [i_1,i_2] [i1,i2]之间一定存在峰值。基于这个结论,我们可以使用二分法来求解问题,初始时 l o w = 0 , h i g h = m − 1 low=0,high=m-1 low=0,high=m1:

  1. i = ⌊ l o w + h i g h 2 ⌋ i=\lfloor \frac{low+high}{2} \rfloor i=2low+high , 第 i i i行的最大值为第 j j j列。
  2. 如果 m a t [ i ] [ j ] < m a t [ i − 1 ] [ j ] mat[i][j] < mat[i-1][j] mat[i][j]<mat[i1][j] ,那么令 h i g h = i − 1 high = i-1 high=i1,继续步骤1。
  3. 如果 m a t [ i ] [ j ] < m a t [ i + 1 ] [ j ] mat[i][j] < mat[i+1][j] mat[i][j]<mat[i+1][j] ,那么令 l o w = i + 1 low = i+1 low=i+1,继续步骤1。
  4. 返回 ( i , j ) (i,j) (i,j)为结果。

使用了这样的方法,我们的时间复杂度为 O ( n l o g m ) O(nlog_m) O(nlogm)

代码实现 ( P y t h o n ) (Python) (Python)
class Solution:
    def findPeakGrid(self, mat: List[List[int]]) -> List[int]:
        m = len(mat)
        #n = len(mat[0])
        low = 0
        high = m-1
        while low <= high:
            i = (low + high)//2 
            j = mat[i].index(max(mat[i]))
            if i-1>=0 and mat[i][j] < mat[i-1][j]:
                high = i-1
                continue
            if i+1 < m and mat[i][j] < mat[i+1][j]:
                low = i + 1
                continue
            return [i,j]
        return None            

题记:


  • 研究生在读,我会尽量保持LeetCode每日一题的思路和代码输出。希望大家多多支持。
  • 水平有限,希望各位大佬能够批评指正。您的教诲是我进步的船帆。
  • 希望各位跟我一样的小白能跟我一起参与到做题和讨论中来。共同进步是我所能期盼的最高愿想。
  • 您的点赞和关注是我坚持分享的动力泉源,希望能将这件简单平凡的事一直做下去。感谢大家。

你可能感兴趣的:(leetcode,算法,数据结构)