leetcode-矩阵中战斗力最弱的 K 行

75 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

题目描述

给你一个大小为 m * n 的矩阵 mat,矩阵由若干军人和平民组成,分别用 1 和 0 表示。
请你返回矩阵中战斗力最弱的 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]

思路

根据题意可知,每行中军人的数量就是战斗力,求出每行的战斗力后,然后根据战斗力和行号进行从小到大排序,取前面的k行即可。所以,核心是快速求出每行1的个数,由于1总是出现在0前面,可以转换成为求最后一个1的下标index,1的个数就是index+1。
我们采用二分法,如果中间点是1,那么中间点的下标可以作为最后一个1位置的备选,更新ans,然后令left = mid + 1再向右试探;如果中间点是0,那么最后一个1肯定还要在更加左边的位置,令right = mid - 1再向左试探。
另外,还需要注意边界情况,即不含有1的情况,所以我们初始化的时候,令ans = -1

Java版本代码

class Solution {
    public int[] kWeakestRows(int[][] mat, int k) {
        int m = mat.length;
        Line[] lineArr = new Line[m];
        for (int i = 0; i < m; i++) {
            lineArr[i] = new Line(count1(mat[i]), i);
        }
        Arrays.sort(lineArr);
        int[] ans = new int[k];
        for (int i = 0; i < k; i++) {
            ans[i] = lineArr[i].getIndex();
        }
        return ans;
    }

    private int count1(int[] arr) {
        int ans = -1;
        int left = 0, right = arr.length-1;
        while (left <= right) {
            int mid = left + ((right-left)>>1);
            if (arr[mid] == 1) {
                ans = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return ans + 1;
    }

    class Line implements Comparable<Line> {
        private int val;
        private int index;

        public int getVal() {
            return val;
        }

        public int getIndex() {
            return index;
        }

        public Line(int val, int index) {
            this.val = val;
            this.index = index;
        }

        @Override
        public int compareTo(Line o) {
            if (val == o.val) {
                return index - o.index;
            }
            return val - o.val;
        }
    }
}