《LeetCode之每日一题》:112.矩阵中战斗力最弱的 K 行

矩阵中战斗力最弱的 K 行


题目链接: 矩阵中战斗力最弱的 K 行

有关题目

给你一个大小为 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 -> 21 -> 42 -> 13 -> 24 -> 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 -> 11 -> 42 -> 13 -> 1 
从最弱到最强对这些行排序后得到 [0,2,3,1]
提示:

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

题解

方法一:硬编码数字

将每一行的士兵数量x100+索引存到一个新的列表里,然后对这个列表进行排序,取前面的k位对100取余即是需要的索引值。
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int sum(int mat[], int col){
    int sum = 0;
    for (int i = 0; i < col ; i++){
        if (mat[i] == 0) break;
        sum += mat[i];
    }
    return sum;
}

int cmp(int* a, int* b){
    return *a - *b;
}
int* kWeakestRows(int** mat, int matSize, int* matColSize, int k, int* returnSize){
    int* list = (int*)malloc(matSize * sizeof(int));
    int* ans = (int*)malloc(k * sizeof(int));

    for (int i = 0; i < matSize; i++){
        list[i] = sum(mat[i], *matColSize) * 100 + i;
    }

    //排序
    qsort(list, matSize, sizeof(int), cmp);

    *returnSize = k;
    for (int i = 0; i < k; i++){
        ans[i] = list[i] % 100;
    }
    return ans;
}

时间复杂度:O(M * N)
空间复杂度:O(M)
方法二:二分查找 + 堆

思路:
题目中保证:军人总是排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。
所以我们使用二分查找,找到最后一个1的位置pos,那么该行军人总数为pos + 1
当我们得到每行的战斗力之后,我们使用一个小根堆来找到最弱的k行的索引
class Solution {
public:
    vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
        int m = mat.size(), n = mat[0].size();
        vector<pair<int, int>> power;//pair类
        for (int i = 0; i < m; ++i) {
            int l = 0, r = n - 1, pos = -1;//二分查找,初始化pos为-1
            while (l <= r) {
                int mid = (l + r) / 2;
                if (mat[i][mid] == 0) {
                    r = mid - 1;
                }
                else {
                    pos = mid;
                    l = mid + 1;
                }
            }
            power.emplace_back(pos + 1, i);
        }

        priority_queue q(greater<pair<int, int>>(), move(power));//小根堆
        vector<int> ans;
        for (int i = 0; i < k; ++i) {//拿出前k个索引
            ans.push_back(q.top().second);
            q.pop();
        }
        return ans;
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值