|
65 | 65 |
|
66 | 66 | <!-- 这里可写通用的实现逻辑 -->
|
67 | 67 |
|
| 68 | +**方法一:前缀和 + 枚举拐点** |
| 69 | + |
| 70 | +首先我们要明确,对于一个乘积,尾随零的个数取决于因子中 $2$ 和 $5$ 的个数的较小值。另外,每一条转角路径应该覆盖尽可能多的数,因此,它一定是从某个边界出发,到达某个拐点,再到达另一个边界。 |
| 71 | + |
| 72 | +因此,我们可以创建四个二维数组 $r2$, $c2$, $r5$, $c5$ 来记录每一行和每一列中 $2$ 和 $5$ 的个数。其中: |
| 73 | + |
| 74 | +- `r2[i][j]` 表示第 $i$ 行中从第 $1$ 列到第 $j$ 列的 $2$ 的个数; |
| 75 | +- `c2[i][j]` 表示第 $j$ 列中从第 $1$ 行到第 $i$ 行的 $2$ 的个数; |
| 76 | +- `r5[i][j]` 表示第 $i$ 行中从第 $1$ 列到第 $j$ 列的 $5$ 的个数; |
| 77 | +- `c5[i][j]` 表示第 $j$ 列中从第 $1$ 行到第 $i$ 行的 $5$ 的个数。 |
| 78 | + |
| 79 | +接下来,我们遍历二维数组 `grid`,对于每个数,我们计算它的 $2$ 和 $5$ 的个数,然后更新四个二维数组。 |
| 80 | + |
| 81 | +然后,我们枚举拐点 $(i, j)$,对于每个拐点,我们计算四个值,其中: |
| 82 | + |
| 83 | +- `a` 表示从 $(i, 1)$ 右移到 $(i, j)$,再从 $(i, j)$ 拐头向上移动到 $(1, j)$ 的路径中 $2$ 的个数和 $5$ 的个数的较小值; |
| 84 | +- `b` 表示从 $(i, 1)$ 右移到 $(i, j)$,再从 $(i, j)$ 拐头向下移动到 $(m, j)$ 的路径中 $2$ 的个数和 $5$ 的个数的较小值; |
| 85 | +- `c` 表示从 $(i, n)$ 左移到 $(i, j)$,再从 $(i, j)$ 拐头向上移动到 $(1, j)$ 的路径中 $2$ 的个数和 $5$ 的个数的较小值; |
| 86 | +- `d` 表示从 $(i, n)$ 左移到 $(i, j)$,再从 $(i, j)$ 拐头向下移动到 $(m, j)$ 的路径中 $2$ 的个数和 $5$ 的个数的较小值。 |
| 87 | + |
| 88 | +每一次枚举,我们取这四个值的最大值,然后更新答案。 |
| 89 | + |
| 90 | +最后,我们返回答案即可。 |
| 91 | + |
| 92 | +时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别是二维数组 `grid` 的行数和列数。 |
| 93 | + |
68 | 94 | <!-- tabs:start -->
|
69 | 95 |
|
70 | 96 | ### **Python3**
|
71 | 97 |
|
72 | 98 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
73 | 99 |
|
74 | 100 | ```python
|
75 |
| - |
| 101 | +class Solution: |
| 102 | + def maxTrailingZeros(self, grid: List[List[int]]) -> int: |
| 103 | + m, n = len(grid), len(grid[0]) |
| 104 | + r2 = [[0] * (n + 1) for _ in range(m + 1)] |
| 105 | + c2 = [[0] * (n + 1) for _ in range(m + 1)] |
| 106 | + r5 = [[0] * (n + 1) for _ in range(m + 1)] |
| 107 | + c5 = [[0] * (n + 1) for _ in range(m + 1)] |
| 108 | + for i, row in enumerate(grid, 1): |
| 109 | + for j, x in enumerate(row, 1): |
| 110 | + s2 = s5 = 0 |
| 111 | + while x % 2 == 0: |
| 112 | + x //= 2 |
| 113 | + s2 += 1 |
| 114 | + while x % 5 == 0: |
| 115 | + x //= 5 |
| 116 | + s5 += 1 |
| 117 | + r2[i][j] = r2[i][j - 1] + s2 |
| 118 | + c2[i][j] = c2[i - 1][j] + s2 |
| 119 | + r5[i][j] = r5[i][j - 1] + s5 |
| 120 | + c5[i][j] = c5[i - 1][j] + s5 |
| 121 | + ans = 0 |
| 122 | + for i in range(1, m + 1): |
| 123 | + for j in range(1, n + 1): |
| 124 | + a = min(r2[i][j] + c2[i - 1][j], r5[i][j] + c5[i - 1][j]) |
| 125 | + b = min(r2[i][j] + c2[m][j] - c2[i][j], r5[i][j] + c5[m][j] - c5[i][j]) |
| 126 | + c = min(r2[i][n] - r2[i][j] + c2[i][j], r5[i][n] - r5[i][j] + c5[i][j]) |
| 127 | + d = min( |
| 128 | + r2[i][n] - r2[i][j - 1] + c2[m][j] - c2[i][j], |
| 129 | + r5[i][n] - r5[i][j - 1] + c5[m][j] - c5[i][j], |
| 130 | + ) |
| 131 | + ans = max(ans, a, b, c, d) |
| 132 | + return ans |
76 | 133 | ```
|
77 | 134 |
|
78 | 135 | ### **Java**
|
79 | 136 |
|
80 | 137 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
81 | 138 |
|
82 | 139 | ```java
|
| 140 | +class Solution { |
| 141 | + public int maxTrailingZeros(int[][] grid) { |
| 142 | + int m = grid.length, n = grid[0].length; |
| 143 | + int[][] r2 = new int[m + 1][n + 1]; |
| 144 | + int[][] c2 = new int[m + 1][n + 1]; |
| 145 | + int[][] r5 = new int[m + 1][n + 1]; |
| 146 | + int[][] c5 = new int[m + 1][n + 1]; |
| 147 | + for (int i = 1; i <= m; ++i) { |
| 148 | + for (int j = 1; j <= n; ++j) { |
| 149 | + int x = grid[i - 1][j - 1]; |
| 150 | + int s2 = 0, s5 = 0; |
| 151 | + for (; x % 2 == 0; x /= 2) { |
| 152 | + ++s2; |
| 153 | + } |
| 154 | + for (; x % 5 == 0; x /= 5) { |
| 155 | + ++s5; |
| 156 | + } |
| 157 | + r2[i][j] = r2[i][j - 1] + s2; |
| 158 | + c2[i][j] = c2[i - 1][j] + s2; |
| 159 | + r5[i][j] = r5[i][j - 1] + s5; |
| 160 | + c5[i][j] = c5[i - 1][j] + s5; |
| 161 | + } |
| 162 | + } |
| 163 | + int ans = 0; |
| 164 | + for (int i = 1; i <= m; ++i) { |
| 165 | + for (int j = 1; j <= n; ++j) { |
| 166 | + int a = Math.min(r2[i][j] + c2[i - 1][j], r5[i][j] + c5[i - 1][j]); |
| 167 | + int b = Math.min(r2[i][j] + c2[m][j] - c2[i][j], r5[i][j] + c5[m][j] - c5[i][j]); |
| 168 | + int c = Math.min(r2[i][n] - r2[i][j] + c2[i][j], r5[i][n] - r5[i][j] + c5[i][j]); |
| 169 | + int d = Math.min(r2[i][n] - r2[i][j - 1] + c2[m][j] - c2[i][j], r5[i][n] - r5[i][j - 1] + c5[m][j] - c5[i][j]); |
| 170 | + ans = Math.max(ans, Math.max(a, Math.max(b, Math.max(c, d)))); |
| 171 | + } |
| 172 | + } |
| 173 | + return ans; |
| 174 | + } |
| 175 | +} |
| 176 | +``` |
83 | 177 |
|
| 178 | +### **C++** |
| 179 | + |
| 180 | +```cpp |
| 181 | +class Solution { |
| 182 | +public: |
| 183 | + int maxTrailingZeros(vector<vector<int>>& grid) { |
| 184 | + int m = grid.size(), n = grid[0].size(); |
| 185 | + vector<vector<int>> r2(m + 1, vector<int>(n + 1)); |
| 186 | + vector<vector<int>> c2(m + 1, vector<int>(n + 1)); |
| 187 | + vector<vector<int>> r5(m + 1, vector<int>(n + 1)); |
| 188 | + vector<vector<int>> c5(m + 1, vector<int>(n + 1)); |
| 189 | + for (int i = 1; i <= m; ++i) { |
| 190 | + for (int j = 1; j <= n; ++j) { |
| 191 | + int x = grid[i - 1][j - 1]; |
| 192 | + int s2 = 0, s5 = 0; |
| 193 | + for (; x % 2 == 0; x /= 2) { |
| 194 | + ++s2; |
| 195 | + } |
| 196 | + for (; x % 5 == 0; x /= 5) { |
| 197 | + ++s5; |
| 198 | + } |
| 199 | + r2[i][j] = r2[i][j - 1] + s2; |
| 200 | + c2[i][j] = c2[i - 1][j] + s2; |
| 201 | + r5[i][j] = r5[i][j - 1] + s5; |
| 202 | + c5[i][j] = c5[i - 1][j] + s5; |
| 203 | + } |
| 204 | + } |
| 205 | + int ans = 0; |
| 206 | + for (int i = 1; i <= m; ++i) { |
| 207 | + for (int j = 1; j <= n; ++j) { |
| 208 | + int a = min(r2[i][j] + c2[i - 1][j], r5[i][j] + c5[i - 1][j]); |
| 209 | + int b = min(r2[i][j] + c2[m][j] - c2[i][j], r5[i][j] + c5[m][j] - c5[i][j]); |
| 210 | + int c = min(r2[i][n] - r2[i][j] + c2[i][j], r5[i][n] - r5[i][j] + c5[i][j]); |
| 211 | + int d = min(r2[i][n] - r2[i][j - 1] + c2[m][j] - c2[i][j], r5[i][n] - r5[i][j - 1] + c5[m][j] - c5[i][j]); |
| 212 | + ans = max({ans, a, b, c, d}); |
| 213 | + } |
| 214 | + } |
| 215 | + return ans; |
| 216 | + } |
| 217 | +}; |
| 218 | +``` |
| 219 | +
|
| 220 | +### **Go** |
| 221 | +
|
| 222 | +```go |
| 223 | +func maxTrailingZeros(grid [][]int) (ans int) { |
| 224 | + m, n := len(grid), len(grid[0]) |
| 225 | + r2 := get(m+1, n+1) |
| 226 | + c2 := get(m+1, n+1) |
| 227 | + r5 := get(m+1, n+1) |
| 228 | + c5 := get(m+1, n+1) |
| 229 | + for i := 1; i <= m; i++ { |
| 230 | + for j := 1; j <= n; j++ { |
| 231 | + x := grid[i-1][j-1] |
| 232 | + s2, s5 := 0, 0 |
| 233 | + for ; x%2 == 0; x /= 2 { |
| 234 | + s2++ |
| 235 | + } |
| 236 | + for ; x%5 == 0; x /= 5 { |
| 237 | + s5++ |
| 238 | + } |
| 239 | + r2[i][j] = r2[i][j-1] + s2 |
| 240 | + c2[i][j] = c2[i-1][j] + s2 |
| 241 | + r5[i][j] = r5[i][j-1] + s5 |
| 242 | + c5[i][j] = c5[i-1][j] + s5 |
| 243 | + } |
| 244 | + } |
| 245 | + for i := 1; i <= m; i++ { |
| 246 | + for j := 1; j <= n; j++ { |
| 247 | + a := min(r2[i][j]+c2[i-1][j], r5[i][j]+c5[i-1][j]) |
| 248 | + b := min(r2[i][j]+c2[m][j]-c2[i][j], r5[i][j]+c5[m][j]-c5[i][j]) |
| 249 | + c := min(r2[i][n]-r2[i][j]+c2[i][j], r5[i][n]-r5[i][j]+c5[i][j]) |
| 250 | + d := min(r2[i][n]-r2[i][j-1]+c2[m][j]-c2[i][j], r5[i][n]-r5[i][j-1]+c5[m][j]-c5[i][j]) |
| 251 | + ans = max(ans, max(a, max(b, max(c, d)))) |
| 252 | + } |
| 253 | + } |
| 254 | + return |
| 255 | +} |
| 256 | +
|
| 257 | +func get(m, n int) [][]int { |
| 258 | + f := make([][]int, m) |
| 259 | + for i := range f { |
| 260 | + f[i] = make([]int, n) |
| 261 | + } |
| 262 | + return f |
| 263 | +} |
| 264 | +
|
| 265 | +func max(a, b int) int { |
| 266 | + if a > b { |
| 267 | + return a |
| 268 | + } |
| 269 | + return b |
| 270 | +} |
| 271 | +
|
| 272 | +func min(a, b int) int { |
| 273 | + if a < b { |
| 274 | + return a |
| 275 | + } |
| 276 | + return b |
| 277 | +} |
84 | 278 | ```
|
85 | 279 |
|
86 | 280 | ### **TypeScript**
|
87 | 281 |
|
88 | 282 | ```ts
|
89 | 283 | function maxTrailingZeros(grid: number[][]): number {
|
90 |
| - let m = grid.length, |
91 |
| - n = grid[0].length; |
92 |
| - let r2 = Array.from({ length: m + 1 }, v => new Array(n + 1).fill(0)), |
93 |
| - c2 = Array.from({ length: m + 1 }, v => new Array(n + 1).fill(0)), |
94 |
| - r5 = Array.from({ length: m + 1 }, v => new Array(n + 1).fill(0)), |
95 |
| - c5 = Array.from({ length: m + 1 }, v => new Array(n + 1).fill(0)); |
96 |
| - for (let i = 1; i <= m; i++) { |
97 |
| - for (let j = 1; j <= n; j++) { |
98 |
| - let cur = grid[i - 1][j - 1]; |
99 |
| - let two = 0, |
100 |
| - five = 0; |
101 |
| - while (cur % 2 == 0) two++, (cur /= 2); |
102 |
| - while (cur % 5 == 0) five++, (cur /= 5); |
103 |
| - r2[i][j] = r2[i - 1][j] + two; |
104 |
| - c2[i][j] = c2[i][j - 1] + two; |
105 |
| - r5[i][j] = r5[i - 1][j] + five; |
106 |
| - c5[i][j] = c5[i][j - 1] + five; |
| 284 | + const m = grid.length; |
| 285 | + const n = grid[0].length; |
| 286 | + const r2 = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0)); |
| 287 | + const c2 = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0)); |
| 288 | + const r5 = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0)); |
| 289 | + const c5 = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0)); |
| 290 | + for (let i = 1; i <= m; ++i) { |
| 291 | + for (let j = 1; j <= n; ++j) { |
| 292 | + let x = grid[i - 1][j - 1]; |
| 293 | + let s2 = 0; |
| 294 | + let s5 = 0; |
| 295 | + for (; x % 2 == 0; x = Math.floor(x / 2)) { |
| 296 | + ++s2; |
| 297 | + } |
| 298 | + for (; x % 5 == 0; x = Math.floor(x / 5)) { |
| 299 | + ++s5; |
| 300 | + } |
| 301 | + r2[i][j] = r2[i][j - 1] + s2; |
| 302 | + c2[i][j] = c2[i - 1][j] + s2; |
| 303 | + r5[i][j] = r5[i][j - 1] + s5; |
| 304 | + c5[i][j] = c5[i - 1][j] + s5; |
107 | 305 | }
|
108 | 306 | }
|
109 | 307 | let ans = 0;
|
110 |
| - function getMin(i0, j0, i1, j1, i3, j3, i4, j4): number { |
111 |
| - // 横向开始、结束,竖向开始、结束 |
112 |
| - const two = c2[i1][j1] - c2[i0][j0] + r2[i4][j4] - r2[i3][j3]; |
113 |
| - const five = c5[i1][j1] - c5[i0][j0] + r5[i4][j4] - r5[i3][j3]; |
114 |
| - return Math.min(two, five); |
115 |
| - } |
116 |
| - for (let i = 1; i <= m; i++) { |
117 |
| - for (let j = 1; j <= n; j++) { |
118 |
| - const leftToTop = getMin(i, 0, i, j, 0, j, i - 1, j), |
119 |
| - leftToBotton = getMin(i, 0, i, j, i, j, m, j), |
120 |
| - rightToTop = getMin(i, j, i, n, 0, j, i, j), |
121 |
| - rightToBotton = getMin(i, j, i, n, i - 1, j, m, j); |
122 |
| - ans = Math.max( |
123 |
| - leftToTop, |
124 |
| - leftToBotton, |
125 |
| - rightToTop, |
126 |
| - rightToBotton, |
127 |
| - ans, |
| 308 | + for (let i = 1; i <= m; ++i) { |
| 309 | + for (let j = 1; j <= n; ++j) { |
| 310 | + const a = Math.min( |
| 311 | + r2[i][j] + c2[i - 1][j], |
| 312 | + r5[i][j] + c5[i - 1][j], |
| 313 | + ); |
| 314 | + const b = Math.min( |
| 315 | + r2[i][j] + c2[m][j] - c2[i][j], |
| 316 | + r5[i][j] + c5[m][j] - c5[i][j], |
| 317 | + ); |
| 318 | + const c = Math.min( |
| 319 | + r2[i][n] - r2[i][j] + c2[i][j], |
| 320 | + r5[i][n] - r5[i][j] + c5[i][j], |
| 321 | + ); |
| 322 | + const d = Math.min( |
| 323 | + r2[i][n] - r2[i][j - 1] + c2[m][j] - c2[i][j], |
| 324 | + r5[i][n] - r5[i][j - 1] + c5[m][j] - c5[i][j], |
128 | 325 | );
|
| 326 | + ans = Math.max(ans, a, b, c, d); |
129 | 327 | }
|
130 | 328 | }
|
131 | 329 | return ans;
|
|
0 commit comments