1
+ # 1351. 统计有序矩阵中的负数
2
+
3
+ > 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
4
+ >
5
+ > 同步博客:https://www.algomooc.com
6
+
7
+ 题目来源于 LeetCode 上 1531 题。
8
+
9
+ ## 题目
10
+
11
+ 给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。
12
+
13
+ 请你统计并返回 grid 中 负数 的数目。
14
+
15
+
16
+ 示例 1:
17
+
18
+
19
+ ```
20
+ 输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
21
+ 输出:8
22
+ 解释:矩阵中共有 8 个负数。
23
+
24
+ ```
25
+
26
+ 示例 2:
27
+
28
+ ```
29
+ 输入:grid = [[3,2],[1,0]]
30
+ 输出:0
31
+ ```
32
+
33
+ 示例 3:
34
+
35
+ ```
36
+ 输入:grid = [[1,-1],[-1,-1]]
37
+ 输出:3
38
+ ```
39
+
40
+ 示例 4:
41
+
42
+
43
+ ```
44
+ 输入:grid = [[-1]]
45
+ 输出:1
46
+
47
+ ```
48
+
49
+
50
+ 提示:
51
+
52
+
53
+ m == grid.length
54
+
55
+ n == grid[i].length
56
+
57
+ 1 <= m, n <= 100
58
+
59
+ -100 <= grid[i][j] <= 100
60
+
61
+
62
+ ## 题目解析
63
+
64
+ 首先审题,在一个矩阵中找出所有负数,这个很好理解,小白一开始做,可以直接暴力遍历,然后依次判断当前值是不是小于0,小于0计数加一。如果是面试的话,面试官一般都会问还没有其他办法,这时候你肯定要说怎么没有,所以我们做一道题不能仅仅限于做出了,要从多方面下手,使得复杂度越小越好。
65
+
66
+ 所以我们要仔细审题,我们看到题目中有这样一句描述**矩阵中的元素无论是按行还是按列,都以非递增顺序排列**,这句话信息量很大,你品,你仔细品。
67
+
68
+ 首先我们可以理解到的是:一个 m * n 的矩阵 grid,grid[i][j]<0的话,i那一行第j个到数组最后一个都是小于0,第i行开始,j到后面的列都是小于0
69
+
70
+ 我们举个例子
71
+
72
+ ```
73
+ [
74
+ [4, 3, -1, -1],
75
+ [3, 2, -1, -1],
76
+ [1, 1, -1, -2],
77
+ [-1, -1, -2, -3]
78
+ ]
79
+
80
+ ```
81
+
82
+ 可以看到第一行第三列的值小于0,那么第一行及后面几行的第三列和后面的列的值都小于0。
83
+
84
+ 所以我们可以进行倒序遍历,找到负数的左边界,也就是左边第一个为负数的值。
85
+
86
+ i为行遍历的指针,j为列遍历指针,count为负数的个数,len1为**当前行**的个数,len2为**当前列**的个数
87
+
88
+ ```
89
+ 初始值
90
+ let count = 0;
91
+ let len1 = grid.length
92
+ let len2 = grid[0].length
93
+ let i = 0;
94
+ let j = len2 - 1;
95
+ ```
96
+
97
+ 然后我们倒序遍历列,行还是正序遍历,以上面的例子来说,我们找到的第一个负数是grid[0][2],然后我们能确定的负数就有如下,所以我们count就可以加上(len1 - i -1) * (len2 - j )
98
+
99
+ ```
100
+ [
101
+ [ -1, -1],
102
+ [ -1, -1],
103
+ [ -1, -2],
104
+ [ -2, -3]
105
+ ]
106
+
107
+ ```
108
+
109
+ 然后我们遍历的矩阵就变成如下,然后重复上面操作。
110
+
111
+
112
+ ```
113
+ [
114
+ [3, 2],
115
+ [1, 1],
116
+ [-1, -1]
117
+ ]
118
+
119
+ ```
120
+
121
+ 所以我们每次遍历后要更新len1和len2,具体看代码和动画。
122
+
123
+
124
+ ## 动画理解
125
+
126
+
127
+ <video id="video" controls="" preload="none" >
128
+ <source id="mp4" src="../Animation/1351.mp4" type="video/mp4">
129
+ </video>
130
+
131
+ ## 参考代码
132
+
133
+ ```JavaScript
134
+ /**
135
+ * @param {number[][]} arr
136
+ * @return {number}
137
+ */
138
+ var countNegatives = function(arr) {
139
+ if (arr.length <= 0 ) {return 0}
140
+ let count = 0;
141
+ let len1 = arr.length;
142
+ let len2 = arr[0].length;
143
+ let i = 0;
144
+ let j = len2 - 1;
145
+ while(i < len1) {
146
+ while(j >= 0) {
147
+ if (arr[i][j] < 0) {
148
+ if (j==0){
149
+ count += (len2 * (len1 - i))
150
+ len2 = 0
151
+ break
152
+ }
153
+ j--
154
+ }else {
155
+ if (len2 == j + 1) {
156
+ break
157
+ }
158
+ count += ((len2 - j - 1) * (len1 - i))
159
+ len2 = j + 1
160
+ break
161
+ }
162
+ }
163
+ i++
164
+ j= len2 - 1
165
+ }
166
+ return count
167
+ };
168
+ ```
169
+
170
+ ## 复杂度分析
171
+
172
+ 时间复杂度: O(mn)。 因为如果矩阵中所有的数都为正数,那么要遍历整个矩阵,所以时间复杂度是O(mn)。
173
+
174
+
175
+ 空间复杂度:O(1)。
176
+
177
+
178
+ 
0 commit comments