1439. 有序矩阵中的第 k 个最小数组和
这里的排序工作我们借助了一下 multiset 来完成
class Solution {
public:
int kthSmallest(vector<vector<int>>& mat, int k) {
vector<int> res(mat[0]);
int m = mat.size(), n = mat[0].size();
for(int i=1;i<m;i++)
{
multiset<int> s;
for(int x: res)
for(int y: mat[i])
s.insert(x+y);
res.assign(s.begin(), s.end());
res.resize(min(k, (int)res.size()));
}
return res[k-1];
}
};
我们先确定左右边界,即最小和与最大和,然后二分得到 m i d mid mid,每次判断和小于 m i d mid mid 的组合有多少个,如果大于等于 k k k 那么更新 r i g h t right right,否则更新 l e f t left left
这就是二分的内容了,但是这道题的关键点不仅仅在于二分,怎么找到可能的组合也是一个问题。
这里,我们采用了类似深搜的算法过程:先有一个初值 s u m sum sum,然后从第 0 层一直往第 m-1 层搜索, i d x idx idx 表示当前在第几层,每次只改变自己所在的这一层的数,改变 s u m sum sum, 如果小于 m i d mid mid 就往下一层搜,大于 m i d mid mid 就返回了
class Solution {
public:
int kthSmallest(vector<vector<int>>& mat, int k) {
int left = 0, right = 0;
for(int i=0;i<mat.size();i++)
{
left += mat[i].front();
right += mat[i].back();
}
int init = left;
while(left<right)
{
int mid = left + (right-left)/2;
int cnt = 1;
dfs(mat, k, mid, 0, init, cnt);
if(cnt<k) left = mid+1;
else right = mid;
}
return right;
}
void dfs(vector<vector<int>>& mat, int k, int maxsum, int idx, int sum, int& cnt )
{
if(idx==mat.size()) return;
if(sum>maxsum || cnt>k) return;
dfs(mat, k, maxsum, idx+1, sum, cnt); // 这层就取首元素,故什么也不做,dfs向下一层
// 不取首元素了,换个数取
for(int j=1;j<mat[idx].size();j++)
{
int tmp = sum+mat[idx][j]-mat[idx][0];
if(tmp>maxsum) break;
cnt++;
dfs(mat, k, maxsum, idx+1, tmp, cnt);
}
}
};