leetcode:162寻找峰值 1901寻找峰值II c语言,二分查找

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

给你一个整数数组 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]

思路:二分查找,直接遍历肯定不行,时间复杂度有限制。这是学习的大佬的代码。我的多了一些判断条件。不如这个。还可以把ans优化掉,直接返回left的值。带入一个例子就能知道代码的巧妙之处,不需要mid左右两边都判断。mid一旦有加减交替就会就会记录峰值,如果mid一直减小正好在0取得峰值。一直增大也是一直记录峰值的。

int findPeakElement(int* nums, int numsSize){
    int left = 0;
    int right = numsSize - 1;
    int ans = 0;
    while(left < right){
        int mid = (right + left) / 2;
        if(nums[mid] < nums[mid + 1]){
            left = mid + 1;
            ans = left;
        }   
        else if(nums[mid] > nums[mid + 1])
            right = mid;
    }
    return ans;
}

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

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

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

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

示例 1:

leetcode:162寻找峰值 1901寻找峰值II c语言,二分查找_第1张图片

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

示例 2:

leetcode:162寻找峰值 1901寻找峰值II c语言,二分查找_第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
  • 任意两个相邻元素均不相等.

思路:这题是上题的升级版。如果做完第一题不久就来做这题可能会踩坑。用两次二分,我就踩了。我一开始想着在一行里面用了二分,找到一行的峰值,然后在峰值所在列再二分。这样思路肯定是有问题的,一行或者一列里面峰值不止一个,而且有的峰值很大,有的峰值很小。

这题正确的思路是用二分确定一行或者一列,然后遍历找出最大值,以行为例,左右两个数肯定不用比较了,因为它是最大值,只需比较上下和当前位置的大小,如果不满足就往大的方向移动。继续二分。

原理:以行为例,由于周围有一圈-1,矩阵里面都为正,那就像一座山,中间高,四周低,按照思路来,比如已知第一行的最大值,如果它不是峰值,证明同列的第二行比它大就往大的那个方向走,找到第二行的最大值再比较,以此类推。我的讲解是顺序的,二分也一样,从中间开始,往大的方向走,因为是二分,跳的很大,可能走过头,回头就行。

必定能找到峰值,因为外圈为-1,假设没有峰值,那第一行最大值必定小于第二行的一个数,那第二行的最大值肯定大于第一行的所有数,上一句话说了。如果没有峰值,那第二行的最大值也必定小于第三行的一个数,不然它就大于周围4个数了。

以此类推,倒数第二行最大值肯定小于倒数第一行的一个数。但是倒数第一行下面是-1所以倒数第一行的最大值大于周围四个数,是峰值。

题解是看的官方的

int maxElement(int *row, int n) {
    int i = 0;
    for (int j = 0; j < n; j++) {
        if (row[i] < row[j]) {
            i = j;
        }
    }
    return i;
}

int* findPeakGrid(int **mat, int matSize, int *matColSize, int *returnSize) {
    int m = matSize, n = matColSize[0];
    int low = 0, high = m - 1;
    while (low <= high) {
        int i = (low + high) / 2;
        int j = maxElement(mat[i], n);
        if (i - 1 >= 0 && mat[i][j] < mat[i - 1][j]) {
            high = i - 1;
            continue;
        }
        if (i + 1 < m && mat[i][j] < mat[i + 1][j]) {
            low = i + 1;
            continue;
        }
        int *ret = (int *)malloc(sizeof(int) * 2);
        ret[0] = i;
        ret[1] = j;
        *returnSize = 2;
        return ret;
    }
    *returnSize = 0;
    return NULL; // impossible
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/find-a-peak-element-ii/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(leetcode,c语言,算法)