Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 731fade

Browse files
author
robot
committed
$2865,$3027
1 parent 85f6d1d commit 731fade

File tree

2 files changed

+314
-0
lines changed

2 files changed

+314
-0
lines changed

problems/2865.beautiful-towers-i.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
2+
## 题目地址(2865. 美丽塔 I - 力扣(LeetCode))
3+
4+
https://leetcode.cn/problems/beautiful-towers-i/description/
5+
6+
## 题目描述
7+
8+
<p>给你一个长度为 <code>n</code>&nbsp;下标从 <strong>0</strong>&nbsp;开始的整数数组&nbsp;<code>maxHeights</code>&nbsp;。</p>
9+
10+
<p>你的任务是在坐标轴上建 <code>n</code>&nbsp;座塔。第&nbsp;<code>i</code>&nbsp;座塔的下标为 <code>i</code>&nbsp;,高度为&nbsp;<code>heights[i]</code>&nbsp;。</p>
11+
12+
<p>如果以下条件满足,我们称这些塔是 <strong>美丽</strong>&nbsp;的:</p>
13+
14+
<ol>
15+
<li><code>1 &lt;= heights[i] &lt;= maxHeights[i]</code></li>
16+
<li><code>heights</code>&nbsp;是一个 <strong>山脉</strong> 数组。</li>
17+
</ol>
18+
19+
<p>如果存在下标 <code>i</code>&nbsp;满足以下条件,那么我们称数组&nbsp;<code>heights</code>&nbsp;是一个 <strong>山脉</strong> 数组:</p>
20+
21+
<ul>
22+
<li>对于所有&nbsp;<code>0 &lt; j &lt;= i</code>&nbsp;,都有&nbsp;<code>heights[j - 1] &lt;= heights[j]</code></li>
23+
<li>对于所有&nbsp;<code>i &lt;= k &lt; n - 1</code>&nbsp;,都有&nbsp;<code>heights[k + 1] &lt;= heights[k]</code></li>
24+
</ul>
25+
26+
<p>请你返回满足 <b>美丽塔</b>&nbsp;要求的方案中,<strong>高度和的最大值</strong>&nbsp;。</p>
27+
28+
<p>&nbsp;</p>
29+
30+
<p><strong class="example">示例 1:</strong></p>
31+
32+
<pre><b>输入:</b>maxHeights = [5,3,4,1,1]
33+
<b>输出:</b>13
34+
<b>解释:</b>和最大的美丽塔方案为 heights = [5,3,3,1,1] ,这是一个美丽塔方案,因为:
35+
- 1 &lt;= heights[i] &lt;= maxHeights[i]
36+
- heights 是个山脉数组,峰值在 i = 0 处。
37+
13 是所有美丽塔方案中的最大高度和。</pre>
38+
39+
<p><strong class="example">示例 2:</strong></p>
40+
41+
<pre><b>输入:</b>maxHeights = [6,5,3,9,2,7]
42+
<b>输出:</b>22
43+
<strong>解释:</strong> 和最大的美丽塔方案为 heights = [3,3,3,9,2,2] ,这是一个美丽塔方案,因为:
44+
- 1 &lt;= heights[i] &lt;= maxHeights[i]
45+
- heights 是个山脉数组,峰值在 i = 3 处。
46+
22 是所有美丽塔方案中的最大高度和。</pre>
47+
48+
<p><strong class="example">示例 3:</strong></p>
49+
50+
<pre><b>输入:</b>maxHeights = [3,2,5,5,2,3]
51+
<b>输出:</b>18
52+
<strong>解释:</strong>和最大的美丽塔方案为 heights = [2,2,5,5,2,2] ,这是一个美丽塔方案,因为:
53+
- 1 &lt;= heights[i] &lt;= maxHeights[i]
54+
- heights 是个山脉数组,最大值在 i = 2 处。
55+
注意,在这个方案中,i = 3 也是一个峰值。
56+
18 是所有美丽塔方案中的最大高度和。
57+
</pre>
58+
59+
<p>&nbsp;</p>
60+
61+
<p><strong>提示:</strong></p>
62+
63+
<ul>
64+
<li><code>1 &lt;= n == maxHeights &lt;= 10<sup>3</sup></code></li>
65+
<li><code>1 &lt;= maxHeights[i] &lt;= 10<sup>9</sup></code></li>
66+
</ul>
67+
68+
69+
## 前置知识
70+
71+
- 单调栈
72+
73+
## 公司
74+
75+
- 暂无
76+
77+
## 思路
78+
79+
朴素的思路是枚举山峰。山峰贪心地取 maxHeight[i],因为取不到 maxHeight[i] 的话后面限制更大不会更优。然后向左向右扩展。扩展的时候除了 maxHeight 限制,还多了一个左边(或者右边)山峰的高度限制。因此可以同时维护一变量 min_v,表示左边(或者右边)山峰的高度,用于限制可以取到的最大值。
80+
81+
直观上来说就是山的高度在扩展的同时不断地下降或者不变,因此我们只需要每次都保证当前的高度都小于等于前面的山峰的高度即可。
82+
83+
```py
84+
ans, n = 0, len(maxHeight)
85+
for i, x in enumerate(maxHeight):
86+
y = t = x
87+
# t 是高度和,y 是 min_v
88+
for j in range(i - 1, -1, -1):
89+
y = min(y, maxHeight[j])
90+
t += y
91+
y = x
92+
for j in range(i + 1, n):
93+
y = min(y, maxHeight[j])
94+
t += y
95+
ans = max(ans, t)
96+
return ans
97+
```
98+
99+
这种做法时间复杂度是 $O(n^2)$,可以通过,这也是为什么这道题分数比较低的原因。
100+
101+
不过这道题还有一种动态规划 + 单调栈的做法。
102+
103+
以向左枚举为例。同样枚举山峰 i,i 取 maxheight[i], 然后找左侧第一个小于它的位置 l(用单调栈)。那么 [l+1, i-1] 之间的位置都能且最多取到 maxHeight[l]。那么 [0, l] 之间的能取到多少呢?这其实相当于以 l 为峰顶左侧的最大和。这不就是一个规模更小的子问题吗?用动态规划即可。
104+
105+
向右也是同理,不再赘述。
106+
107+
## 关键点
108+
109+
- 单调栈优化
110+
- 动态规划
111+
112+
## 代码
113+
114+
- 语言支持:Python3
115+
116+
Python3 Code:
117+
118+
```python
119+
120+
class Solution:
121+
def maximumSumOfHeights(self, maxHeight: List[int]) -> int:
122+
n = len(maxHeight)
123+
f = [-1] * n # f[i] 表示 i 作为峰顶左侧的高度和
124+
g = [-1] * n # g[i] 表示 -i-1 作为峰顶右侧的高度和
125+
def gao(f):
126+
st = []
127+
for i in range(len(maxHeight)):
128+
while st and maxHeight[i] <= maxHeight[st[-1]]:
129+
st.pop()
130+
if st:
131+
f[i] = (i - st[-1]) * maxHeight[i] + f[st[-1]]
132+
else:
133+
f[i] = maxHeight[i] * (i + 1)
134+
st.append(i)
135+
gao(f)
136+
maxHeight = maxHeight[::-1]
137+
gao(g)
138+
maxHeight = maxHeight[::-1]
139+
ans = 0
140+
for i in range(len(maxHeight)):
141+
ans = max(ans, f[i] + g[-i-1] - maxHeight[i])
142+
return ans
143+
144+
```
145+
146+
147+
**复杂度分析**
148+
149+
令 n 为数组长度。
150+
151+
- 时间复杂度:$O(n)$
152+
- 空间复杂度:$O(n)$
153+
154+
155+
> 此题解由 [力扣刷题插件](https://leetcode-pp.github.io/leetcode-cheat/?tab=solution-template) 自动生成。
156+
157+
力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~
158+
159+
以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
160+
161+
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
162+
163+
![](https://p.ipic.vip/h9nm77.jpg)
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
## 题目地址(3027. 人员站位的方案数 II - 力扣(LeetCode))
2+
3+
https://leetcode.cn/problems/find-the-number-of-ways-to-place-people-ii/
4+
5+
## 题目描述
6+
7+
<p>给你一个&nbsp;&nbsp;<code>n x 2</code>&nbsp;的二维数组 <code>points</code>&nbsp;,它表示二维平面上的一些点坐标,其中&nbsp;<code>points[i] = [x<sub>i</sub>, y<sub>i</sub>]</code>&nbsp;。</p>
8+
9+
<p>我们定义 x 轴的正方向为 <strong>右</strong>&nbsp;(<strong>x 轴递增的方向</strong>),x 轴的负方向为 <strong>左</strong>&nbsp;(<strong>x 轴递减的方向</strong>)。类似的,我们定义 y 轴的正方向为 <strong>上</strong>&nbsp;(<strong>y 轴递增的方向</strong>),y 轴的负方向为 <strong>下</strong>&nbsp;(<strong>y 轴递减的方向</strong>)。</p>
10+
11+
<p>你需要安排这 <code>n</code>&nbsp;个人的站位,这 <code>n</code>&nbsp;个人中包括 Alice 和 Bob 。你需要确保每个点处&nbsp;<strong>恰好</strong>&nbsp;&nbsp;<strong>一个</strong>&nbsp;人。同时,Alice 想跟 Bob 单独玩耍,所以&nbsp;Alice 会以 Bob<b>&nbsp;</b>的坐标为 <strong>左上角</strong>&nbsp;,Bob 的坐标为 <strong>右下角</strong>&nbsp;建立一个矩形的围栏(<strong>注意</strong>,围栏可能&nbsp;<strong>不</strong> 包含任何区域,也就是说围栏可能是一条线段)。如果围栏的 <strong>内部</strong>&nbsp;或者 <strong>边缘</strong>&nbsp;上有任何其他人,Alice 都会难过。</p>
12+
13+
<p>请你在确保 Alice&nbsp;<strong>不会</strong> 难过的前提下,返回 Alice 和 Bob 可以选择的 <strong>点对</strong>&nbsp;数目。</p>
14+
15+
<p><b>注意</b>,Alice 建立的围栏必须确保 Alice 的位置是矩形的左上角,Bob 的位置是矩形的右下角。比方说,以&nbsp;<code>(1, 1)</code>&nbsp;,<code>(1, 3)</code>&nbsp;,<code>(3, 1)</code>&nbsp;&nbsp;<code>(3, 3)</code>&nbsp;为矩形的四个角,给定下图的两个输入,Alice 都不能建立围栏,原因如下:</p>
16+
17+
<ul>
18+
<li>图一中,Alice 在&nbsp;<code>(3, 3)</code>&nbsp;且 Bob 在&nbsp;<code>(1, 1)</code>&nbsp;,Alice 的位置不是左上角且 Bob 的位置不是右下角。</li>
19+
<li>图二中,Alice 在&nbsp;<code>(1, 3)</code>&nbsp;且 Bob 在&nbsp;<code>(1, 1)</code>&nbsp;,Bob 的位置不是在围栏的右下角。</li>
20+
</ul>
21+
<img alt="" src="https://assets.leetcode.com/uploads/2024/01/04/example0alicebob-1.png" style="width: 750px; height: 308px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem;">
22+
<p>&nbsp;</p>
23+
24+
<p><strong class="example">示例 1:</strong></p>
25+
26+
<p><img alt="" src="https://assets.leetcode.com/uploads/2024/01/04/example1alicebob.png" style="width: 376px; height: 308px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem;"></p>
27+
28+
<pre><b>输入:</b>points = [[1,1],[2,2],[3,3]]
29+
<b>输出:</b>0
30+
<strong>解释:</strong>没有办法可以让 Alice 的围栏以 Alice 的位置为左上角且 Bob 的位置为右下角。所以我们返回 0 。
31+
</pre>
32+
33+
<p><strong class="example">示例 2:</strong></p>
34+
35+
<p><strong class="example"><a href="https://pic.leetcode.cn/1706880313-YelabI-example2.jpeg"><img alt="" src="https://pic.leetcode.cn/1708226715-CxjXKb-20240218-112338.jpeg" style="width: 900px; height: 248px;"></a></strong></p>
36+
37+
<pre><b>输入:</b>points = [[6,2],[4,4],[2,6]]
38+
<b>输出:</b>2
39+
<b>解释:</b>总共有 2 种方案安排 Alice 和 Bob 的位置,使得 Alice 不会难过:
40+
- Alice 站在 (4, 4) ,Bob 站在 (6, 2) 。
41+
- Alice 站在 (2, 6) ,Bob 站在 (4, 4) 。
42+
不能安排 Alice 站在 (2, 6) 且 Bob 站在 (6, 2) ,因为站在 (4, 4) 的人处于围栏内。
43+
</pre>
44+
45+
<p><strong class="example">示例 3:</strong></p>
46+
47+
<p><strong class="example"><a href="https://pic.leetcode.cn/1706880311-mtPGYC-example3.jpeg"><img alt="" src="https://pic.leetcode.cn/1708226721-wTbEuK-20240218-112351.jpeg" style="width: 911px; height: 250px;"></a></strong></p>
48+
49+
<pre><b>输入:</b>points = [[3,1],[1,3],[1,1]]
50+
<b>输出:</b>2
51+
<b>解释:</b>总共有 2 种方案安排 Alice 和 Bob 的位置,使得 Alice 不会难过:
52+
- Alice 站在 (1, 1) ,Bob 站在 (3, 1) 。
53+
- Alice 站在 (1, 3) ,Bob 站在 (1, 1) 。
54+
不能安排 Alice 站在 (1, 3) 且 Bob 站在 (3, 1) ,因为站在 (1, 1) 的人处于围栏内。
55+
注意围栏是可以不包含任何面积的,上图中第一和第二个围栏都是合法的。
56+
</pre>
57+
58+
<p>&nbsp;</p>
59+
60+
<p><strong>提示:</strong></p>
61+
62+
<ul>
63+
<li><code>2 &lt;= n &lt;= 1000</code></li>
64+
<li><code>points[i].length == 2</code></li>
65+
<li><code>-10<sup>9</sup> &lt;= points[i][0], points[i][1] &lt;= 10<sup>9</sup></code></li>
66+
<li><code>points[i]</code>&nbsp;点对两两不同。</li>
67+
</ul>
68+
69+
## 前置知识
70+
71+
- 暂无
72+
73+
## 公司
74+
75+
- 暂无
76+
77+
## 思路
78+
79+
为了方便确定谁是 alice,谁是 bob,首先我们按 x 正序排序。
80+
81+
令索引 i 是 alice (x1, y1),索引 j != i 的都**可能**作为 bob(x2, y2)。那什么样的 j 满足条件呢?需要满足:
82+
83+
1. alice 纵坐标要大于等于 bob(横坐标由于排序已经保证了 alice 不大于 bob,满足题目要求)
84+
85+
2. 中间的点纵坐标要么比两人都大,要么比两人都小。(即中间的点的纵坐标不能位于 alice 和 bob 中间)
86+
87+
有一个特殊的 case: alice 和 bob 的横坐标相等,这种情况下如果 i 的纵坐标小于 j 的纵坐标,不一定是不满足题意的。因此 alice 和 bob 横坐标相等,因此我们可以将 alice 看成是 bob, bob 看成是 alice。经过这样的处理,就又满足题意了。
88+
89+
为了不做这种特殊处理,我们可以按照 x 正序排序的同时,对 x 相同的按照 y 逆序排序,这样就不可能出现横坐标相同,i 的纵坐标小于 j 的纵坐标的情况。另外这样在 i 确定的时候,i 前面的点也一定不是 j,因此只需要枚举 i 之后的点即可。
90+
91+
> 这样会错过一些情况吗?不会!因为这种 case 会在其他遍历的时候中枚举到。
92+
93+
因此我们可以枚举 i 为 alice, j > i 为 bob。然后枚举 i 个 j 中间的点是否满足题意(不在 i 和 j 中间的不用看)。
94+
95+
接下来,我们看如何满足前面提到的两点。
96+
97+
对于第一点,只需比较 alice 和 bob 的 y 即可。
98+
99+
对于第二点,我们只需要记录最大的 y 即可。只要 y2 大于最大的 y 就行。如果 y2 <= max <= y1,那么就不行,否则可以。 其中 max 是 最可能在 alice 和 bob 之间的 y,这样不需要全部比较。这个所谓最可能得就是最大的 y。
100+
101+
大家可以结合图来理解。
102+
103+
![](https://p.ipic.vip/i52ibj.png)
104+
105+
如图,虚点是 i 和 j 中间的点。对于这些点只要纵坐标****在图上的两个横线之间就行。因此这些点的纵坐标****要么大于 y1,要么小于 y2。换句话说,这些点的纵坐标要么最小值大于 y1,要么最大值小于 y2。因此我们只需要记录最大的 y 即可。
106+
107+
## 关键点
108+
109+
- 排序
110+
111+
## 代码
112+
113+
- 语言支持:Python3
114+
115+
Python3 Code:
116+
117+
```python
118+
119+
class Solution:
120+
def numberOfPairs(self, points: List[List[int]]) -> int:
121+
points.sort(key=lambda p: (p[0], -p[1]))
122+
ans = 0
123+
for i, (x1, y1) in enumerate(points): # point i
124+
max_y = -inf
125+
min_y = inf
126+
for (x2, y2) in points[i + 1:]: # point j
127+
if y1 < y2: continue # 确保条件1
128+
if y2 > max_y or y1 < min_y: # 确保条件2
129+
ans += 1
130+
max_y = max(max_y, y2)
131+
min_y = min(min_y, y2)
132+
return ans
133+
134+
```
135+
136+
**复杂度分析**
137+
138+
令 n 为 points 长度。
139+
140+
- 时间复杂度:$O(nlogn)$
141+
- 空间复杂度:$O(1)$
142+
143+
> 此题解由 [力扣刷题插件](https://leetcode-pp.github.io/leetcode-cheat/?tab=solution-template) 自动生成。
144+
145+
力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~
146+
147+
以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
148+
149+
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
150+
151+
![](https://p.ipic.vip/h9nm77.jpg)

0 commit comments

Comments
 (0)