题目链接
Leetcode.2146 价格范围内最高排名的 K 样物品
rating : 1837
题目描述
给你一个下标从
0
0
0 开始的二维整数数组
g
r
i
d
grid
grid ,它的大小为 m x n
,表示一个商店中物品的分布图。数组中的整数含义为:
0
表示无法穿越的一堵墙。1
表示可以自由通过的一个空格子。- 所有其他正整数表示该格子内的一样物品的价格。你可以自由经过这些格子。
从一个格子走到上下左右相邻格子花费1
步。
同时给你一个整数数组
p
r
i
c
i
n
g
pricing
pricing 和
s
t
a
r
t
start
start ,其中 pricing = [low, high]
且 start = [row, col]
,表示你开始位置为 (row, col)
,同时你只对物品价格在 闭区间
[
l
o
w
,
h
i
g
h
]
[low, high]
[low,high] 之内的物品感兴趣。同时给你一个整数
k
k
k 。
你想知道给定范围 内 且 排名最高 的 k k k 件物品的 位置 。排名按照优先级从高到低的以下规则制定:
- 距离:定义为从
start
到一件物品的最短路径需要的步数(较近 距离的排名更高)。 - 价格:较低 价格的物品有更高优先级,但只考虑在给定范围之内的价格。
- 行坐标:较小 行坐标的有更高优先级。
- 列坐标:较小 列坐标的有更高优先级。
请你返回给定价格内排名最高的 k k k 件物品的坐标,将它们按照排名排序后返回。如果给定价格内少于 k k k 件物品,那么请将它们的坐标 全部 返回。
示例 1:
输入:grid = [[1,2,0,1],[1,3,0,1],[0,2,5,1]], pricing = [2,5], start = [0,0], k = 3
输出:[[0,1],[1,1],[2,1]]
解释:起点为 (0,0) 。
价格范围为 [2,5] ,我们可以选择的物品坐标为 (0,1),(1,1),(2,1) 和 (2,2) 。
这些物品的排名为:
- (0,1) 距离为 1
- (1,1) 距离为 2
- (2,1) 距离为 3
- (2,2) 距离为 4 所以,给定价格范围内排名最高的 3 件物品的坐标为 (0,1),(1,1) 和 (2,1) 。
示例 2:
输入:grid = [[1,2,0,1],[1,3,3,1],[0,2,5,1]], pricing = [2,3], start = [2,3], k = 2
输出:[[2,1],[1,2]]
解释:起点为 (2,3) 。
价格范围为 [2,3] ,我们可以选择的物品坐标为 (0,1),(1,1),(1,2) 和 (2,1) 。
这些物品的排名为:
- (2,1) 距离为 2 ,价格为 2
- (1,2) 距离为 2 ,价格为 3
- (1,1) 距离为 3
- (0,1) 距离为 4 所以,给定价格范围内排名最高的 2 件物品的坐标为 (2,1) 和 (1,2) 。
示例 3:
输入:grid = [[1,1,1],[0,0,1],[2,3,4]], pricing = [2,3], start = [0,0], k = 3
输出:[[2,1],[2,0]]
解释:起点为 (0,0) 。
价格范围为 [2,3] ,我们可以选择的物品坐标为 (2,0) 和 (2,1) 。
这些物品的排名为:
- (2,1) 距离为 5
- (2,0) 距离为 6 所以,给定价格范围内排名最高的 2 件物品的坐标为 (2,1) 和 (2,0) 。 注意,k = 3 但给定价格范围内只有 2 件物品。
提示:
- m = g r i d . l e n g t h m = grid.length m=grid.length
- n = g r i d [ i ] . l e n g t h n = grid[i].length n=grid[i].length
- 1 ≤ m , n ≤ 1 0 5 1 \leq m, n \leq 10^5 1≤m,n≤105
- 1 ≤ m × n ≤ 105 1 \leq m \times n \leq 105 1≤m×n≤105
- 0 ≤ g r i d [ i ] [ j ] ≤ 105 0 \leq grid[i][j] \leq 105 0≤grid[i][j]≤105
- p r i c i n g . l e n g t h = 2 pricing.length = 2 pricing.length=2
- 2 ≤ l o w ≤ h i g h ≤ 105 2 \leq low \leq high \leq 105 2≤low≤high≤105
- s t a r t . l e n g t h = 2 start.length = 2 start.length=2
- 0 ≤ r o w ≤ m − 1 0 \leq row \leq m - 1 0≤row≤m−1
- 0 ≤ c o l ≤ n − 1 0 \leq col \leq n - 1 0≤col≤n−1
- g r i d [ r o w ] [ c o l ] > 0 grid[row][col] > 0 grid[row][col]>0
- 1 ≤ k ≤ m × n 1 \leq k \leq m \times n 1≤k≤m×n
解法:bfs + 排序
用 d i s t dist dist 记录从起点 ( s t a r t [ 0 ] , s t a r t [ 1 ] ) (start[0] , start[1]) (start[0],start[1]) 到每一个位置的最短距离。
在遍历的过程中我们只记录价格 g r i d [ i ] [ j ] grid[i][j] grid[i][j] 在 [ p r i c i n g [ 0 ] , p r i c i n g [ 1 ] ] [pricing[0] , pricing[1]] [pricing[0],pricing[1]]区间的位置。
记录的形式为 {距离,价格,位置}
,即
{
d
i
s
t
[
i
]
[
j
]
,
g
r
i
d
[
i
]
[
j
]
,
(
i
,
j
)
}
\{dist[i][j] , grid[i][j] , (i,j) \}
{dist[i][j],grid[i][j],(i,j)}。
然后对其进行排序:
- 如果距离不一样,距离小的排在前面;
- 如果价格不一样,价格小的排在前面;
- 如果行坐标不一样,行坐标小的排在前面;
- 如果列坐标不一样,列坐标小的排在前面;
排序完之后,我们取前 k k k 个元素的位置,将其插入答案数组 a n s ans ans 即可。
时间复杂度: O ( m × n + m × n × l o g ( m × n ) ) O(m \times n + m \times n \times log(m \times n)) O(m×n+m×n×log(m×n))
C++代码:
using PII = pair<int,int>;
const int dx[4] = {1,0,-1,0};
const int dy[4] = {0,1,0,-1};
class Solution {
public:
vector<vector<int>> highestRankedKItems(vector<vector<int>>& grid, vector<int>& pricing, vector<int>& start, int k) {
vector<vector<int>> ans;
int l = pricing[0] , r = pricing[1];
int m = grid.size() , n = grid[0].size();
vector<vector<int>> dist(m,vector<int>(n,1e9));
vector<tuple<int,int,PII>> a;
queue<PII> q;
dist[start[0]][start[1]] = 0;
q.emplace(start[0],start[1]);
while(!q.empty()){
auto [x,y] = q.front();
q.pop();
int p = grid[x][y];
if(p >= l && p <= r){
auto t = make_tuple(dist[x][y],p,make_pair(x,y));
a.emplace_back(t);
}
for(int i = 0;i < 4;i++){
int nx = x + dx[i] , ny = y + dy[i];
if(nx < 0 || nx >= m || ny < 0 || ny >= n || grid[nx][ny] == 0 || dist[nx][ny] != 1e9) continue;
dist[nx][ny] = dist[x][y] + 1;
q.emplace(nx,ny);
}
}
sort(a.begin(),a.end(),[&](auto &a,auto &b){
int d1 = get<0>(a) , d2 = get<0>(b);
int p1 = get<1>(a) , p2 = get<1>(b);
int x1 = get<2>(a).first , y1 = get<2>(a).second;
int x2 = get<2>(b).first , y2 = get<2>(b).second;
if(d1 != d2) return d1 < d2;
else if(p1 != p2) return p1 < p2;
else if(x1 != x2) return x1 < x2;
else return y1 < y2;
});
int len = min((int)a.size() , k);
for(int i = 0;i < len;i++){
auto x = get<2>(a[i]).first , y = get<2>(a[i]).second;
ans.push_back({x,y});
}
return ans;
}
};