1. 程式人生 > 其它 >面試演算法題 尋找矩陣的極小值

面試演算法題 尋找矩陣的極小值

AcWing 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 l = 0, r = n -1;
        
        while (l < r){
            int mid = l + r >> 1;//去mid列
            
            int k;//記錄列裡面最小值的位置
            LL val = INF;//取最小值過程中可能會爆int, 取LL
            
            
            //查詢列裡面最小值
            for (int i = 0; i < n; i ++){
                int t = query(i,mid);
                if(t < val){
                    val = t;
                    k = i;
                }
            }
            
            
            LL left = mid ? query(k, mid -1) :INF;// 特判下mid是不是邊界
            LL right = mid + 1 < n ? query(k, mid + 1):INF;
            
            // 進行mid判斷,可以篩掉一半的列
            if(val < left && val < right) return {k,mid};
            if(left < val) r = mid  - 1;
            else l = mid + 1;
        }
        
        
        //得到最後r==l ,找該列中最小值即符合條件
        int k;
        LL val = INF;
        
        for (int i = 0; i < n; i ++){
            int t = query(i, r);
            if(t < val){
                val = t;
                k = i;
            }
        }
        
        return {k,r};
    }
};