一、题目
二、分析
- 暴力
- 二分法 + 优先队列(最小堆)
二分法节省计算军人数目的时间,时间复杂度从 O ( m ∗ n ) O(m*n) O(m∗n)降到 O ( m ∗ l o g ( n ) ) O(m*log(n)) O(m∗log(n)),使用最小堆(C++提供STLpriority_queue
可以快速建立最小堆)对军人数目排序,最后出队。建立最小堆的时间为 O ( m ) O(m) O(m),需要 O ( k ∗ l o g ( m ) ) O(k*log(m)) O(k∗log(m))的时间从堆中取出 k 个最小的元素。所以时间复杂度为: O ( m ∗ l o g ( n ) + k ∗ l o g ( m ) ) O(m*log(n) + k*log(m)) O(m∗log(n)+k∗log(m))。
三、代码
3.1 暴力
class Solution {
public:
vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
int m(mat.size()), n(mat[0].size());
vector<int> junrenNumber(m), result(k);
// 找出每一行的军人数目
for (int i = 0; i < m; i++)
{
junrenNumber[i] = 0;
for (int j = 0; j < n; j++)
{
junrenNumber[i] = (mat[i][j] == 1) ? junrenNumber[i] + 1 : junrenNumber[i];
}
}
// 找出前 k 个(从小到大)军人数目最少的行
for (int i = 0; i < k; i++)
{
int minValue = INT_MAX, minIndex(0);
for(int j = 0; j < m; j++)
{
if (junrenNumber[j] != -1 && junrenNumber[j] < minValue)
{
minValue = junrenNumber[j];
minIndex = j;
}
}
junrenNumber[minIndex] = -1;
result[i] = minIndex;
}
return result;
}
};
3.2 二分法 + 优先队列(最小堆)
class Solution {
public:
vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
int m(mat.size()), n(mat[0].size());
vector<int> result;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int,int>>> c;
// 使用二分法初始化优先队列,优先队列按照最小堆排序(从小到大排序,最小值先出队),由于需要其下标,所以优先队列采用pair。
for (int i = 0; i < m; i++)
{
int middle, l(0), r(n-1);
while (l <= r)
{
middle = (l + r) / 2;
if (mat[i][middle] == 0)
{
r = middle - 1;
}
else
{
l = middle + 1;
}
}
int number = (mat[i][middle] == 1) ? middle + 1 : middle;
// 注意:优先队列排序,先按照pair的第一个值排序,相等则按照第二个值排序。
c.push({number, i});
}
while (!c.empty())
{
result.push_back(c.top().second);
if (result.size() == k)
{
break;
}
c.pop();
}
return result;
}
};
执行用时:12 ms, 在所有 C++ 提交中击败了86.08%的用户
内存消耗:10.3 MB, 在所有 C++ 提交中击败了20.99%的用户
四、参考文章
1. 最大堆(创建、删除、插入和堆排序)
2. c++优先队列(priority_queue)用法详解
3. priority_queue用法(大顶堆,小顶堆)总结
4. 优先队列priority_queue中使用pair对的方法