1452. 寻找矩阵的极小值

给定一个 n×n 的矩阵,矩阵中包含 n×n 个 互不相同 的整数。

定义极小值:如果一个数的值比与它相邻的所有数字的值都小,则这个数值就被称为极小值。

一个数的相邻数字是指其上下左右四个方向相邻的四个数字,另外注意,处于边界或角落的数的相邻数字可能少于四个。

要求在 O(nlogn) 的时间复杂度之内找出任意一个极小值的位置,并输出它在第几行第几列。

本题中矩阵是隐藏的,你可以通过我们预设的 int 函数 query 来获得矩阵中某个位置的数值是多少。

例如,query(a,b) 即可获得矩阵中第 a 行第 b 列的位置的数值。

注意:

矩阵的行和列均从 0 开始编号。
query()函数的调用次数不能超过 (n+2)×⌈log2n⌉+n。
答案不唯一,输出任意一个极小值的位置即可。
数据范围
1≤n≤300,矩阵中的整数在int范围内。

输入样例:

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

输出样例:

[0, 0]

代码

// Forward declaration of queryAPI.
// int query(int x, int y);
// return int means matrix[x][y].

class Solution {
public:
    vector<int> getMinimumValue(int n) {
        typedef long long LL;
        const LL INF=1e15;//可能爆int
        int l=0,r=n-1;//矩阵下标从0开始数
        int mid,k;
        LL t;
        //结论:按列划分,l和r之间一定有极小值,注意点:r和l所指向的列也是未访问过的
        //注意点:不可以按行和列交替二分,该方法不正确
        while(l<r){
            LL val=INF;
            mid=l+r>>1;//求中间那列的列下标值
            for(int i=0;i<n;i++){//寻找中间那列的最小值
                t=query(i,mid);//获取第i行第mid列的值
                if(t<val){//如果当前值小比记录的最小值小
                    val=t;//更新最小值
                    k=i;//更新最小值所在的行
                }
            }//注意:防止数组越界
            LL left=mid?query(k,mid-1):INF;//求中间列最小值所在行左边的值
            LL right=mid<n-1?query(k,mid+1):INF;//求中间列最小值所在行右边的值
            //如果中间列(上下都大于它)最小值的左边及右边的值都小于它,即四周都大于它,则其为极小值之一
            if(val<left&&val<right)
                return {k,mid};//输出其下标
            else if(left<val)//如果中间列最小值左边的值小于中间列最小值
                r=mid-1;//则中间列最小值左边一定有极小值
            else //如果中间列最小值右边的值小于中间列最小值,左右都有随便选一边即可
                l=mid+1;//则中间列最小值右边一定有极小值
        }
        //l和r之间一定有极小值,当l=r时,该列的最小值就是极小值
        LL val=INF;
        for(int i=0;i<n;i++){
            t=query(i,r);
            if(t<val){
                val=t;
                k=i;
            }
        }
        return {k,r};//输出极小值的下标
    }
};

你可能感兴趣的:(算法笔试面试常考题)