Skip to content

Commit 6227245

Browse files
committed
update sth
1 parent ef5895b commit 6227245

File tree

2 files changed

+237
-0
lines changed

2 files changed

+237
-0
lines changed

docs/ondoing/1139.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
2+
3+
## 暴力法
4+
在做这道题目之前,我们先看数据规模 $10^2$,很小。
5+
6+
我们分析题意,题意要求是 **边界全部为 1 的最大正方形**
7+
8+
从这个题意我们可以看出什么?
9+
1. 什么是正方形?或者正方形可以有什么来决定?
10+
- 左上角和右下角可以决定一个矩形,然后长和宽决定该矩形是否是正方形
11+
12+
2. 限定条件是边长上面都是 1
13+
14+
因此,本题的暴力求解是:
15+
1. 枚举所有的左上角和右下角
16+
- 判断是否能够构成正方形
17+
- 判断正方形的边长上是否都是 1
18+
19+
写出套路就是:
20+
```
21+
for 所有的左上角:
22+
for 所有的右下角:
23+
if(左上角+右下角能构成正方形) {
24+
tmp = isValid(正方形是否边长上都是 1)
25+
if(tmp) {
26+
则更新答案
27+
}
28+
}
29+
30+
```
31+
32+
```javascript
33+
/**
34+
* @param {number[][]} grid
35+
* @return {number}
36+
*/
37+
var largest1BorderedSquare = function(grid) {
38+
if(!grid.length || !grid[0].length) return 0;
39+
40+
let m = grid.length;
41+
let n = grid[0].length;
42+
let ans = 0;
43+
44+
for(let i = 0; i < m; i++) {
45+
for(let j = 0; j < n; j++) {
46+
for(let k = i; k < m; k++) {
47+
for(let p = j; p < n; p++) {
48+
if(k - i !== p - j) continue;
49+
let tmp = isValid(i,j,k,p);
50+
if(tmp) ans = Math.max(ans, k-i+1);
51+
52+
}
53+
}
54+
}
55+
}
56+
57+
return ans * ans;
58+
59+
function isValid(i,j,k,p) {
60+
for(let m = i; m <= k; m++) {
61+
if(!grid[m][j] || !grid[m][p]) return false;
62+
}
63+
64+
for(let m = j; m <= p; m++) {
65+
if(!grid[i][m] || !grid[k][m]) return false;
66+
}
67+
68+
return true;
69+
}
70+
};
71+
```
72+
73+
**复杂度分析**:
74+
- 时间复杂度: $O(m*n*min(m,n)^2 + m^2*n^2)$
75+
- 空间复杂度:$O(1)$
76+
77+
在上面我们的算法当中,是可以优化的。
78+
我们在上面的做法是同时枚举所有的**左上角****右下角**
79+
其实我们将右下角换成对于正方形边长的枚举,这样会减少不少的判断。
80+
81+
```
82+
for 所有的左上角:
83+
for 所有的可能正方形边长:
84+
tmp = isValid(正方形是否边长上都是 1)
85+
if(tmp) {
86+
则更新答案
87+
}
88+
89+
```
90+
91+
核心代码变为:
92+
```javascript
93+
94+
for(let i = 0; i < m; i++) {
95+
for(let j = 0; j < n; j++) {
96+
let len = Math.min(m-i, n-j);
97+
for(let k = 1; k <= len; k++) {
98+
let tmp = isValid(i,j,k);
99+
if(tmp) ans = Math.max(ans, k);
100+
}
101+
}
102+
}
103+
```
104+
105+
- 时间复杂度: $O(m*n*min(m,n)^2)$
106+
107+
108+
## 动态规划
109+
你会发现,每次变动一下左上角,所有的边长我们都得重新判断。我们是否能够保留上次的计算结果来避免重复运算呢。
110+
111+
真正符合题目要求的边长都是 1,因此我们可以通过这个得到一个问题:所有符合要求的正方形边长,为左上角开始的最大连续 1 的个数(左边和下边)。
112+
113+
在这里,我们可以枚举右下角,求右下角的左边和上边的最长连续 1 的个数。这样,我们可以缓存已经枚举过点的结果。
114+
115+
$$
116+
up[i][j] =
117+
\begin{cases}
118+
0, grid[i][j] = 0 \\
119+
up[i-1][j] + 1, grid[i][j] = 1
120+
\end{cases}
121+
$$
122+
123+
$$
124+
left[i][j] =
125+
\begin{cases}
126+
0, grid[i][j] = 0 \\
127+
left[i][j-1] + 1, grid[i][j] = 1
128+
\end{cases}
129+
$$
130+
131+
如何判断这个正方形呢?
132+
1. 下边和右边,由 $len = Math.min(left[i][j], up[i][j])$ 决定, 然后枚举 $[len ,1]$ 找到第一个符合要求的边长
133+
2. 上边和左边,可以分别通过右上角的 left 和左下角的 up 来获取。
134+
135+
这样,我们就将 $isValid$ 的时间复杂度降低到了 $O(1)$
136+
137+
138+
```javascript
139+
/**
140+
* @param {number[][]} grid
141+
* @return {number}
142+
*/
143+
var largest1BorderedSquare = function(grid) {
144+
if(!grid.length || !grid[0].length) return 0;
145+
146+
let m = grid.length;
147+
let n = grid[0].length;
148+
let ans = 0;
149+
150+
let up = new Array(m+1);
151+
let left = new Array(m+1);
152+
153+
for(let i = 0; i <= m; i++) {
154+
up[i] = new Array(n+1).fill(0);
155+
left[i] = new Array(n+1).fill(0);
156+
}
157+
158+
for(let i = 0; i < m; i++) {
159+
for(let j = 0; j < n; j++) {
160+
if(grid[i][j] === 1) {
161+
up[i+1][j+1] = up[i][j+1] + 1
162+
left[i+1][j+1] = left[i+1][j] + 1;
163+
164+
let len = Math.min(up[i+1][j+1], left[i+1][j+1]);
165+
166+
while(len) {
167+
if (i+1 >= len && j+1 >= len &&left[i-len+2][j+1] >= len && up[i+1][j-len+2] >= len) break;
168+
169+
len--;
170+
}
171+
ans = Math.max(ans, len);
172+
173+
}
174+
}
175+
}
176+
177+
return ans * ans;
178+
};
179+
180+
```
181+
182+
**复杂度分析**:
183+
- 时间复杂度: $O(m*n*min(m,n))$
184+
- 空间复杂度:$O(m*n)$

docs/ondoing/740.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
## 动态规划
3+
转换成小偷问题。
4+
5+
```javascript
6+
/**
7+
* @param {number[]} nums
8+
* @return {number}
9+
*/
10+
var deleteAndEarn = function(nums) {
11+
let counter = new Array(10001).fill(0);
12+
13+
for(let i = 0; i < nums.length; i++) {
14+
counter[nums[i]]++;
15+
}
16+
17+
let dp = new Array(counter.length).fill(0);
18+
19+
dp[1] = counter[1];
20+
for(let i = 2; i < counter.length; i++) {
21+
dp[i] = Math.max(dp[i-1], dp[i-2] + counter[i]*i);
22+
}
23+
24+
return dp[counter.length-1];
25+
};
26+
```
27+
28+
**滚动数组优化**
29+
30+
```javascript
31+
/**
32+
* @param {number[]} nums
33+
* @return {number}
34+
*/
35+
var deleteAndEarn = function(nums) {
36+
let counter = new Array(10001).fill(0);
37+
38+
for(let i = 0; i < nums.length; i++) {
39+
counter[nums[i]]++;
40+
}
41+
42+
let dp0 = 0;
43+
let dp1 = counter[1];
44+
45+
for(let i = 2; i < counter.length; i++) {
46+
let tmp = dp1;
47+
dp1 = Math.max(dp1, dp0 + counter[i]*i);
48+
dp0 = tmp;
49+
}
50+
51+
return dp1;
52+
};
53+
```

0 commit comments

Comments
 (0)