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]
思路
這道題我們通過二分的思想解決,我們假設一個如下5 * 5
的矩陣
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
肉眼可見,我們直接就可以看出本矩陣的極小值是1
,但是我們怎麼實現合格問題呢?
我們先從中間列也就是第2
列將矩陣分爲兩部分,左和右,之後我們從中間列從上到下第一個元素開始遍歷中間列,找到中間列的最小值,可以看到,最小值是3
,隨後我們對比3
的左右元素,如果這時3
的左右元素都> 3
,那很幸運,3
就是矩陣的極小值,如果3
的左右元素有< 3
的,那麼我們只需要再次二分這半部分矩陣即可,因爲這半部分矩陣中,一定存在極小值
系統給我們提供了query(x, y)
函數來獲取矩陣中(x, y)
位置的元素,但是有使用次數限制,這裏的限制證明過程過於繁瑣,我們只需要儘量降低query(x, y)
函數的使用次數即可
最後經過不斷二分操作,矩陣一定只剩下一列,這時我們只需要取這一列的最小值即可,這個值便是整個矩陣的極小值!代碼如下:
代碼
class Solution {
public:
vector<int> getMinimumValue(int n) {
long INF = 1e15;
int l = 0, r = n - 1;
int k;
while (l < r) {
int mid = (l + r) / 2;
long min = INF;
for (int i = 0; i < n; ++i) {
int val = query(i, mid);
if (min >= val) {
min = val;
k = i;
}
}
long left = mid ? query(k, mid - 1) : INF;
long right = (mid + 1) < n ? query(k, mid + 1) : INF;
if (left > min && right > min)
return{ k, mid };
if (left < min)
r = mid - 1;
else
l = mid + 1;
}
long min = INF;
for (int i = 0; i < n; i++) {
int val = query(i, r);
if (min > val) {
min = val;
k = i;
}
}
return { k, r };
}
};