【二分查找】leetcode 1351. 统计有序矩阵中的负数

1351. 统计有序矩阵中的负数

题目描述

给你一个 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

提示

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 100
  • -100 <= grid[i][j] <= 100

方法一:暴力

解题思路

一个个遍历矩阵的所有数字,统计所有负数。

代码

class Solution {
public:
    int countNegatives(vector<vector<int>>& grid) {
        int ans = 0;
        for(auto x: grid)
            for(auto y: x)
                if(y < 0)
                    ans++;
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(nm)。
  • 空间复杂度:O(1)。

方法二:二分查找

解题思路

矩阵中的元素无论是按行还是按列,都以非递增顺序排列,所以可以利用二分查找来找到每行中的第一个负数,从这个位置到末尾便是每行中负数的个数,最后累计起来。

代码

class Solution {
public:
    int countNegatives(vector<vector<int>>& grid) {
        int ans = 0;
        int m = grid.size();
        int n = grid[0].size();
        for(int i = 0; i < m; i++)
        {
            int l = 0, r = n - 1, mid;
            while(l < r)
            {
                mid = l + (r - l) / 2;
                if(grid[i][mid] < 0)    r = mid;
                else    l = mid + 1;
            }
            if(grid[i][l] < 0)  ans += n - l;
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O( n l o g m nlogm nlogm)。
  • 空间复杂度:O(1)。

方法三:倒序遍历

解题思路

整个矩阵是每行每列均非递增,说明了每一行从前往后第一个负数的位置是不断递减的。
考虑我们已经算出第 i 行的从前往后第一个负数的位置 p o s i pos_i posi ,那么第 i+1 行的时候, p o s i + 1 pos_{i + 1} posi+1 的位置肯定是位于 [ 0 , p o s i ] [0, pos_i] [0,posi] 中,所以对于第 i+1 行我们倒着从 p o s i pos_i posi循环找 p o s i + 1 pos_{i + 1} posi+1 即可,这个循环起始变量是一直在递减的。

代码

class Solution {
public:
    int countNegatives(vector<vector<int>>& grid) {
        int ans = 0;
        int m = grid.size(), n = grid[0].size(), pos = grid[0].size() - 1;
        for(int i = 0; i < m; i++)
        {
            int j;
            for(j = pos; j >= 0; j--)
                if(grid[i][j] >= 0)
                {
                    if(j + 1 < n)
                    {
                        pos = j + 1;
                        ans += n - pos;
                    }
                    break;
                }
            if(j == - 1)
            {  
                ans += n;
                pos = -1;
            }
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O( n + m n + m n+m)。
  • 空间复杂度:O(1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值