# 最大矩形
题目: 给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例:
输入:
[
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
输出: 6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximal-rectangle
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 这个题相当的复杂,在 LeetCode 上也是困难的难度
# 思路
- 根据示例看出,
找出最大矩形的范围是所有都包含1的,形成的矩形。
- 从新排列二位数组,把所有的0去掉,在记录每个1的开始和结束位置
例如上面示例可以改变成
[[0, 0], [2, 2]] [[0, 0], [2, 4]] [[0, 4]] [[0, 0], [3, 3]
1
2
3
4 - 找出没两行之间的交集点,例如:1 和 2 2和3
// 1 和 2 的交集点 [2,2] // 2 和 3 的交集点 [2, 4]
1
2
3
4- 以此类推,递归找出所有的交集点
function maximalRectangle(ary) {
let res = []
// 提取所有的 1 至少两个以上
let reg = /1{2,}/g
// 把 二维数组中,相邻的 1 提取提取出来 (起始点 和 结束点)这部的结果 [[1,3], [5, 6]]
ary = ary.map(item => {
const str = item.join('')
let r = reg.exec(str)
// 存储临时的结果, 上面分析第二步的结果
let pr = []
// 使用循环,把所有的匹配结果都拿到
while (r) {
pr.push([r.index, r.index + r[0].length - 1])
r = reg.exec(str)
}
return pr
})
// return
// 递归找出所有的相邻的矩形
// c 的意思是处理的行数
let maxRect = (ary, res, c = 1) => {
// 拿出两行的数据,进行计算相交点, 上面第三步骤 (需要所有的数组都要比较)
const pre = ary.pop()
const next = ary.pop()
// 记录第一行的每个开始和结束的点
let pp
// 记录第二行的每个开始和结束的点
let nn
// 记录交叉的开始索引
let start = false
// 记录交叉的结束索引
let end = false
// 最小宽度
let minWidth = 1
// 最大的宽度
let maxWidth = 1
c ++
// 交集遍历,找出两行的交叉点
for (let i = 0; i < pre.length; i++) {
pp = pre[i]
for (let j = 0; j < next.length; j++) {
nn = next[j]
// 起始点 - 开始点
minWidth = Math.min(pp[1], nn[1]) - Math.max(pp[0] - nn[0])
// 如果最小宽度大于 最大宽度
if (minWidth > maxWidth) {
maxWidth = minWidth
// 这里 start 取最大值,end 取最小的值
start = Math.max(pp[0], nn[0])
end = Math.min(pp[1], nn[1])
}
}
}
// 如果没有找到交叉的点
if (!start || !end) {
// c 小于 3,说明没有找到交叉的点
if (c < 3) {
return false
} else {
// top[0][1] - top[0][0] + 1 什么意思?
// 例如 [[2,4]] 意思是 4 - 2 算出宽度, + 1 是因为索引是 0 开始的,所以要 + 1
minWidth = pre[0][1] - pre[0][0] + 1
// 如果大于 1 说明是 矩形
if (minWidth > 1) {
// 为什么 c - 1 因为 当 c 等于 3 的时候,其实才计算了两行的交叉
res.push((c - 1) * minWidth) // 长 * 宽 计算面积
}
}
} else { // 如果找到结果
// 如果找到了,就把开始和结束位置放进去,进行下一次循环
ary.push([[start, end]])
maxRect(ary, res, c++)
}
}
// 计算所有的行数,
while(ary.length > 1) {
maxRect([].concat(ary), res)
ary.pop()
}
// 去最大值
let max = 0
let item = res.pop()
while(item) {
if (item > max) {
max = item
}
item = res.pop()
}
return max > 0 ? max : -1
}
console.log(maximalRectangle([["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]])) // 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96