小鱼刷leetcode---1337. 矩阵中战斗力最弱的 K 行

85 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情

一 描述

1337. 矩阵中战斗力最弱的 K 行 - 力扣(LeetCode) (leetcode-cn.com)

给你一个大小为 m * n 的矩阵 mat,矩阵由若干军人和平民组成,分别用 10 表示。

请你返回矩阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。

如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。

军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。

 

示例 1:

输入:mat = 
[[1,1,0,0,0],
 [1,1,1,1,0],
 [1,0,0,0,0],
 [1,1,0,0,0],
 [1,1,1,1,1]], 
k = 3
输出:[2,0,3]
解释:
每行中的军人数目:
行 0 -> 2 
行 1 -> 4 
行 2 -> 1 
行 3 -> 2 
行 4 -> 5 
从最弱到最强对这些行排序后得到 [2,0,3,1,4]

示例 2:

输入:mat = 
[[1,0,0,0],
 [1,1,1,1],
 [1,0,0,0],
 [1,0,0,0]], 
k = 2
输出:[0,2]
解释: 
每行中的军人数目:
行 0 -> 1 
行 1 -> 4 
行 2 -> 1 
行 3 -> 1 
从最弱到最强对这些行排序后得到 [0,2,3,1]

提示:

  • m == mat.length
  • n == mat[i].length
  • 2 <= n, m <= 100
  • 1 <= k <= m
  • matrix[i][j] 不是 0 就是 1

二 分析

题目要求我们求出战斗力最弱的 k 行,因此我们需要先统计每行的战斗力(即 1 的个数),然后再从中取出 1 的个数最少的 k 行。

对于如何统计每行的 1 的个数,注意到题目条件:军人总是排在一行中的靠前位置,也就是说 1 总是出现在 0 之前,因此我们可以直接搜索 1 和 0 的分界的地方,找到这个分界点不就知道了 1 的个数了。

对于怎样找出所有行中 1 的个数最少的 k 行,可以使用堆这种数据结构,每次从堆中取出 1 的个数最少的那行。

三 答案

class Solution {
public:
    struct cmp {
        bool operator() (const pair<int, int>& a, const pair<int, int>& b) {
            //如果两行的战斗力相同,我们就比较下标
            if (a.second == b.second) {
                return a.first > b.first;
            }
            return a.second > b.second;
        }
    };
    
    vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
        priority_queue<pair<int, int>,          //第一元素代表行的下标,第二元素代表行的战斗力
                       vector<pair<int, int>>,
                       cmp> pque;
                       
        int n = mat.size(), m = mat[0].size();
        //对矩阵中的每行进行二分法
        for (int i = 0; i < n; ++i) {
            int left = 0, right = m;
            while (left < right) {
                int mid = (right - left) / 2 + left;
                if (mat[i][mid] == 0) {
                    right = mid;
                } else {
                    left = mid + 1;
                }
            }
            //找到了分界点,就放进堆中
            pque.push({i, left});
        }

        vector<int> res;
        //从优先队列中取出战斗力最弱的 k 行
        while (k--) {
            res.push_back(pque.top().first);
            pque.pop();
        }
        return res;
    }
};