leetcode_1351 统计有序矩阵中的负数

172 阅读2分钟

要求

给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。 

请你统计并返回 grid 中 负数 的数目。

示例 1:

输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
输出:8
解释:矩阵中共有 8 个负数。

示例 2:

输入:grid = [[3,2],[1,0]]
输出:0

示例 3:

输入:grid = [[1,-1],[-1,-1]]
输出:3

示例 4:

输入:grid = [[-1]]
输出:1

核心代码

class Solution:
    def countNegatives(self, grid: List[List[int]]) -> int:
        if not grid and not grid[0]:
            return 0
        m,n  = len(grid),len(grid[0])

        res = 0
        for i in range(m):
            for j in range(n):
                if grid[i][j] < 0:
                    res += 1
        return res 

另一解法

class Solution:
    def countNegatives(self, grid: List[List[int]]) -> int:
        if not grid and not grid[0]:
            return 0
        m,n  = len(grid),len(grid[0])
        
        res = 0
        for i in range(m):
            if grid[i][0] < 0:
                break
            for j in range(n):
                if grid[i][j] < 0:
                    break
                res += 1
        return m *n - res 

第三解法

class Solution:
    def countNegatives(self, grid: List[List[int]]) -> int:
        if not grid and not grid[0]:
            return 0
        m,n  = len(grid),len(grid[0])

        def findFirstNegativeElementIndex(l):
            left, right = 0, len(l) - 1
            while left <= right:
                mid = (left + right) // 2
                
                if l[mid] >= 0:
                    left = mid + 1
                else:
                    right = mid - 1
            return left

        res = 0
        for i in range(m):
            cnt = findFirstNegativeElementIndex(grid[i])
            res += cnt
        return m *n - res 

image.png

重点问题

解题思路:

第一种解法:我们使用两层循环的方式,遇到负数,统计个数加一,比较低效,时间复杂度:O(MN),空间复杂度:O(1);第二种解法:我们使用两层循环的方式,遇到负数,非递增,不用向下进行循环,中断,我们统计的是正数的个数,最终使用全部的元素个数减去正数的个数,就是负数的个数;时间复杂度:O(MN),最坏情况下全部为正数,跟上一种思路的时间复杂度相同,空间复杂度:O(1);第三种解法:因为我们看到了题目中出现非递增的字样,知道已经排好序了,所以我们可以使用二分查找的方式辅助查找到第一个负数的位置,时间复杂度:O(MlogN)空间复杂度:O(1)优化:时间复杂度也可以为O(NlogM),实际实现中应根据MN的大小选择行二分或者列二分,加快算法速度。