Skip to content

Commit b52ebff

Browse files
committed
feat: 2320
1 parent 562e625 commit b52ebff

6 files changed

+327
-21
lines changed

CMakeLists.txt

+2-18
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,6 @@ include_directories(cn/C++/algm)
77

88
add_executable(1-two-sum leetcode/editor/cn/1-two-sum.cpp leetcode/editor/cn/headers.h)
99

10-
add_executable(2-add-two-numbers leetcode/editor/cn/2-add-two-numbers.cpp)
11-
add_executable(15-3sum leetcode/editor/cn/15-3sum.cpp)
12-
add_executable(70-climbing-stairs leetcode/editor/cn/70-climbing-stairs.cpp)
13-
add_executable(51-n-queens leetcode/editor/cn/51-n-queens.cpp)
14-
add_executable(62-unique-paths leetcode/editor/cn/62-unique-paths.cpp)
15-
add_executable(343-integer-break leetcode/editor/cn/343-integer-break.cpp)
16-
add_executable(416-partition-equal-subset-sum leetcode/editor/cn/416-partition-equal-subset-sum.cpp)
17-
add_executable(1046-last-stone-weight leetcode/editor/cn/1046-last-stone-weight.cpp)
18-
add_executable(1049-last-stone-weight-ii leetcode/editor/cn/1049-last-stone-weight-ii.cpp)
19-
add_executable(2765-longest-alternating-subarray leetcode/editor/cn/2765-longest-alternating-subarray.cpp)
2010
add_executable(contest contest.cpp leetcode/editor/cn/headers.h)
21-
add_executable(518-coin-change-ii leetcode/editor/cn/518-coin-change-ii.cpp)
22-
add_executable(322-coin-change leetcode/editor/cn/322-coin-change.cpp)
23-
add_executable(139-word-break leetcode/editor/cn/139-word-break.cpp)
24-
add_executable(213-house-robber-ii leetcode/editor/cn/213-house-robber-ii.cpp)
25-
add_executable(337-house-robber-iii leetcode/editor/cn/337-house-robber-iii.cpp)
26-
add_executable(122-best-time-to-buy-and-sell-stock-ii leetcode/editor/cn/122-best-time-to-buy-and-sell-stock-ii.cpp)
27-
add_executable(123-best-time-to-buy-and-sell-stock-iii leetcode/editor/cn/123-best-time-to-buy-and-sell-stock-iii.cpp)
28-
add_executable(300-longest-increasing-subsequence leetcode/editor/cn/300-longest-increasing-subsequence.cpp)
11+
add_executable(376-wiggle-subsequence leetcode/editor/cn/376-wiggle-subsequence.cpp)
12+
add_executable(2320-count-number-of-ways-to-place-houses leetcode/editor/cn/2320-count-number-of-ways-to-place-houses.cpp)

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ headers.h 文件所在路径: `leetcode/editor/cn/headers.h`
8585

8686
## 2.贪心算法
8787
- [ ] 455-分发饼干
88-
- [ ] 376-摆动序列
88+
- [ ] [376-摆动序列](./leetcode/editor/cn/376-wiggle-subsequence.cpp)
8989

90-
## 2.回溯法
90+
## 3.回溯法
9191

9292
- [ ] 980-不同路径III
9393

@@ -99,7 +99,7 @@ headers.h 文件所在路径: `leetcode/editor/cn/headers.h`
9999

100100
### 动态规划篇(先按分数排序, 刷完后再分类)
101101

102-
- [ ] 2320-统计放置房子的方式数
102+
- [x] [2320-统计放置房子的方式数](./leetcode/editor/cn/2320-count-number-of-ways-to-place-houses.cpp)
103103
- [ ] 2140-解决智力问题
104104
- [ ] 2321-拼接数组的最大分数
105105
- [ ] 2266-统计打字方案数
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//一条街道上共有 n * 2 个 地块 ,街道的两侧各有 n 个地块。每一边的地块都按从 1 到 n 编号。每个地块上都可以放置一所房子。
2+
//
3+
// 现要求街道同一侧不能存在两所房子相邻的情况,请你计算并返回放置房屋的方式数目。由于答案可能很大,需要对 10⁹ + 7 取余后再返回。
4+
//
5+
// 注意,如果一所房子放置在这条街某一侧上的第 i 个地块,不影响在另一侧的第 i 个地块放置房子。
6+
//
7+
//
8+
//
9+
// 示例 1:
10+
//
11+
// 输入:n = 1
12+
//输出:4
13+
//解释:
14+
//可能的放置方式:
15+
//1. 所有地块都不放置房子。
16+
//2. 一所房子放在街道的某一侧。
17+
//3. 一所房子放在街道的另一侧。
18+
//4. 放置两所房子,街道两侧各放置一所。
19+
//
20+
//
21+
// 示例 2:
22+
// 输入:n = 2
23+
//输出:9
24+
//解释:如上图所示,共有 9 种可能的放置方式。
25+
//
26+
//
27+
//
28+
//
29+
// 提示:
30+
//
31+
//
32+
// 1 <= n <= 10⁴
33+
//
34+
//
35+
// Related Topics 动态规划 👍 30 👎 0
36+
37+
38+
#include "headers.h"
39+
40+
//leetcode submit region begin(Prohibit modification and deletion)
41+
class Solution {
42+
public:
43+
// 考虑单侧 + 乘法原理 + 空间优化
44+
int countHousePlacements5(int n) {
45+
if (n == 1) return 4;
46+
int mod = 1e9 + 7;
47+
auto a = 1ull, b = 2ull, c = 3ull;
48+
// 1. dp[i]: 单侧i个方块的摆放房子数目
49+
// 2. 第 i 个方块摆放房子: dp[i] = dp[i-2]
50+
// 第 i 个方块不摆放房子: dp[i] = dp[i-1]
51+
// 所以, dp[i] = dp[i-1] + dp[i-2]
52+
for (int i = 2; i <= n; ++i) {
53+
c = (b + a) % mod;
54+
a = b;
55+
b = c;
56+
}
57+
// 乘法原理: 左边独立摆放方式 * 右边独立摆放方式
58+
return (c * c) % mod;
59+
}
60+
// 考虑单侧 + 乘法原理
61+
int countHousePlacements(int n) {
62+
if (n == 1) return 4;
63+
vector<unsigned long long> dp(n + 1, 0);
64+
int mod = 1e9 + 7;
65+
dp[0] = 1;
66+
dp[1] = 2;
67+
// 1. dp[i]: 单侧i个方块的摆放房子数目
68+
// 2. 第 i 个方块摆放房子: dp[i] = dp[i-2]
69+
// 第 i 个方块不摆放房子: dp[i] = dp[i-1]
70+
// 所以, dp[i] = dp[i-1] + dp[i-2]
71+
for (int i = 2; i <= n; ++i) {
72+
dp[i] = (dp[i - 1] + dp[i - 2]) % mod;
73+
}
74+
// 乘法原理: 左边独立摆放方式 * 右边独立摆放方式
75+
return (dp[n] * dp[n]) % mod;
76+
}
77+
int countHousePlacements3(int n) {
78+
if (n == 1) return 4;
79+
vector<vector<unsigned long long>> dp(n, vector<unsigned long long>(4, 1));
80+
int mod = 1e9 + 7;
81+
// 1. dp[i][j]: n=i的时候,三种状态下的放置方式
82+
// j=0, 说明第n行没有房子
83+
// j=1, 说明第n行左边有一个房子
84+
// j=2, 说明第n行右边有一个房子
85+
// j=3, 说明第n行有两个房子
86+
// 2. 递推公式
87+
// dp[i][0] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2] + dp[i-1][3]
88+
// dp[i][1] = dp[i-1][2] + dp[i-1][0]
89+
// dp[i][2] = dp[i-1][1] + dp[i-1][0]
90+
// dp[i][3] = dp[i-1][0]
91+
for (int i = 1; i < n; ++i) {
92+
dp[i][0] = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3]) % mod;
93+
dp[i][1] = (dp[i - 1][2] + dp[i - 1][0]) % mod;
94+
dp[i][2] = (dp[i - 1][1] + dp[i - 1][0]) % mod;
95+
dp[i][3] = dp[i - 1][0];
96+
}
97+
return (dp[n - 1][0] + dp[n - 1][1] + dp[n - 1][2] + dp[n - 1][3]) % mod;
98+
}
99+
// 优化空间
100+
int countHousePlacements2(int n) {
101+
if (n == 1) return 4;
102+
vector<unsigned long long> dp(4, 1);
103+
int mod = 1e9 + 7;
104+
// 1. dp[i][j]: n=i的时候,三种状态下的放置方式
105+
// j=0, 说明第n行没有房子
106+
// j=1, 说明第n行左边有一个房子
107+
// j=2, 说明第n行右边有一个房子
108+
// j=3, 说明第n行有两个房子
109+
// 2. 递推公式
110+
// dp[i][0] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2] + dp[i-1][3]
111+
// dp[i][1] = dp[i-1][2] + dp[i-1][0]
112+
// dp[i][2] = dp[i-1][1] + dp[i-1][0]
113+
// dp[i][3] = dp[i-2][0] + dp[i-2][1] + dp[i-2][2] + dp[i-1][3]
114+
for (int i = 1; i < n; ++i) {
115+
int a0 = dp[0];
116+
dp[2] = dp[1] + dp[0];
117+
dp[0] = (dp[0] + dp[1] * 2 + dp[3]) % mod;
118+
dp[3] = a0;
119+
dp[1] = dp[2];
120+
}
121+
return (dp[0] + dp[1] + dp[2] + dp[3]) % mod;
122+
}
123+
};
124+
//leetcode submit region end(Prohibit modification and deletion)
125+
126+
127+
int main() {
128+
Solution s;
129+
int res;
130+
cout << (res = s.countHousePlacements(1)) << endl;
131+
assert(4 == res);
132+
cout << (res = s.countHousePlacements(2)) << endl;
133+
assert(9 == res);
134+
cout << (res = s.countHousePlacements(10)) << endl;
135+
assert(20736 == res);
136+
cout << (res = s.countHousePlacements(1000)) << endl;
137+
assert(500478595 == res);
138+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也
2+
//视作摆动序列。
3+
//
4+
//
5+
// 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
6+
// 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一
7+
//个差值为零。
8+
//
9+
//
10+
// 子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
11+
//
12+
// 给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
13+
//
14+
//
15+
//
16+
// 示例 1:
17+
//
18+
//
19+
//输入:nums = [1,7,4,9,2,5]
20+
//输出:6
21+
//解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。
22+
//
23+
//
24+
// 示例 2:
25+
//
26+
//
27+
//输入:nums = [1,17,5,10,13,15,10,5,16,8]
28+
//输出:7
29+
//解释:这个序列包含几个长度为 7 摆动序列。
30+
//其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。
31+
//
32+
//
33+
// 示例 3:
34+
//
35+
//
36+
//输入:nums = [1,2,3,4,5,6,7,8,9]
37+
//输出:2
38+
//
39+
//
40+
//
41+
//
42+
// 提示:
43+
//
44+
//
45+
// 1 <= nums.length <= 1000
46+
// 0 <= nums[i] <= 1000
47+
//
48+
//
49+
//
50+
//
51+
// 进阶:你能否用 O(n) 时间复杂度完成此题?
52+
//
53+
// Related Topics 贪心 数组 动态规划 👍 979 👎 0
54+
55+
56+
#include "headers.h"
57+
58+
//leetcode submit region begin(Prohibit modification and deletion)
59+
class Solution {
60+
public:
61+
// 贪心算法
62+
int wiggleMaxLength(vector<int> &nums) {
63+
64+
}
65+
66+
// 动态规划
67+
int wiggleMaxLength2(vector<int> &nums) {
68+
int n = nums.size();
69+
vector<vector<int>> dp(n, vector<int>(2, 1));
70+
// 1. dp[i][j]: 以 i 为截止的最长子序列, j=0: 前一个差值为负数, j=1: 前一个差值为正数
71+
// 2. for(i: 1->n-1)
72+
// for(j: 0->i-1)
73+
// if (nums[i] > nums[j])
74+
// dp[i][1] = max(dp[i][1], dp[j][0] + 1);
75+
// else if (nums[i] < nums[j])
76+
// dp[i][0] = max(dp[i][0], dp[j][1] + 1);
77+
int res = 1;
78+
for (int i = 1; i < n; ++i) {
79+
for (int j = 0; j < i; ++j) {
80+
if (nums[i] > nums[j])
81+
dp[i][1] = max(dp[i][1], dp[j][0] + 1);
82+
else if (nums[i] < nums[j])
83+
dp[i][0] = max(dp[i][0], dp[j][1] + 1);
84+
}
85+
res = max(res, max(dp[i][0], dp[i][1]));
86+
}
87+
showVector2(dp);
88+
return res;
89+
}
90+
};
91+
//leetcode submit region end(Prohibit modification and deletion)
92+
93+
94+
int main() {
95+
Solution s;
96+
vector<int> arr{1, 7, 4, 9, 2, 5};
97+
assert(s.wiggleMaxLength(arr) == 6);
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<p>一条街道上共有 <code>n * 2</code> 个 <strong>地块</strong> ,街道的两侧各有 <code>n</code> 个地块。每一边的地块都按从 <code>1</code> 到 <code>n</code> 编号。每个地块上都可以放置一所房子。</p>
2+
3+
<p>现要求街道同一侧不能存在两所房子相邻的情况,请你计算并返回放置房屋的方式数目。由于答案可能很大,需要对 <code>10<sup>9</sup> + 7</code> 取余后再返回。</p>
4+
5+
<p>注意,如果一所房子放置在这条街某一侧上的第 <code>i</code> 个地块,不影响在另一侧的第 <code>i</code> 个地块放置房子。</p>
6+
7+
<p>&nbsp;</p>
8+
9+
<p><strong>示例 1:</strong></p>
10+
11+
<pre><strong>输入:</strong>n = 1
12+
<strong>输出:</strong>4
13+
<strong>解释:</strong>
14+
可能的放置方式:
15+
1. 所有地块都不放置房子。
16+
2. 一所房子放在街道的某一侧。
17+
3. 一所房子放在街道的另一侧。
18+
4. 放置两所房子,街道两侧各放置一所。
19+
</pre>
20+
21+
<p><strong>示例 2:</strong></p>
22+
<img alt="" src="https://assets.leetcode.com/uploads/2022/05/12/arrangements.png" style="width: 500px; height: 500px;"> <pre><strong>输入:</strong>n = 2
23+
<strong>输出:</strong>9
24+
<strong>解释:</strong>如上图所示,共有 9 种可能的放置方式。
25+
</pre> </img>
26+
27+
<p>&nbsp;</p>
28+
29+
<p><strong>提示:</strong></p>
30+
31+
<ul>
32+
<li><code>1 &lt;= n &lt;= 10<sup>4</sup></code></li>
33+
</ul>
34+
35+
<div><div>Related Topics</div><div><li>动态规划</li></div></div><br><div><li>👍 30</li><li>👎 0</li></div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<p>如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为<strong> 摆动序列 。</strong>第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。</p>
2+
3+
<ul>
4+
<li> <p>例如,&nbsp;<code>[1, 7, 4, 9, 2, 5]</code> 是一个 <strong>摆动序列</strong> ,因为差值 <code>(6, -3, 5, -7, 3)</code>&nbsp;是正负交替出现的。</p> </li>
5+
<li>相反,<code>[1, 4, 7, 2, 5]</code>&nbsp;&nbsp;<code>[1, 7, 4, 5, 5]</code> 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。</li>
6+
</ul>
7+
8+
<p><strong>子序列</strong> 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。</p>
9+
10+
<p>给你一个整数数组 <code>nums</code> ,返回 <code>nums</code> 中作为 <strong>摆动序列 </strong>的 <strong>最长子序列的长度</strong> 。</p>
11+
12+
<p>&nbsp;</p>
13+
14+
<p><strong>示例 1:</strong></p>
15+
16+
<pre>
17+
<strong>输入:</strong>nums = [1,7,4,9,2,5]
18+
<strong>输出:</strong>6
19+
<strong>解释:</strong>整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。
20+
</pre>
21+
22+
<p><strong>示例 2:</strong></p>
23+
24+
<pre>
25+
<strong>输入:</strong>nums = [1,17,5,10,13,15,10,5,16,8]
26+
<strong>输出:</strong>7
27+
<strong>解释:</strong>这个序列包含几个长度为 7 摆动序列。
28+
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。
29+
</pre>
30+
31+
<p><strong>示例 3:</strong></p>
32+
33+
<pre>
34+
<strong>输入:</strong>nums = [1,2,3,4,5,6,7,8,9]
35+
<strong>输出:</strong>2
36+
</pre>
37+
38+
<p>&nbsp;</p>
39+
40+
<p><strong>提示:</strong></p>
41+
42+
<ul>
43+
<li><code>1 &lt;= nums.length &lt;= 1000</code></li>
44+
<li><code>0 &lt;= nums[i] &lt;= 1000</code></li>
45+
</ul>
46+
47+
<p>&nbsp;</p>
48+
49+
<p><strong>进阶:</strong>你能否用&nbsp;<code>O(n)</code><em> </em>时间复杂度完成此题?</p>
50+
51+
<div><div>Related Topics</div><div><li>贪心</li><li>数组</li><li>动态规划</li></div></div><br><div><li>👍 979</li><li>👎 0</li></div>

0 commit comments

Comments
 (0)