Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1b906da

Browse files
Update
1 parent6da25b8 commit1b906da

File tree

4 files changed

+202
-12
lines changed

4 files changed

+202
-12
lines changed

‎README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@
357357
|[0491.递增子序列](https://github.com/youngyangyang04/leetcode/blob/master/problems/0491.递增子序列.md)|深度优先搜索|中等|**深度优先搜索/回溯算法** 这个去重有意思|
358358
|[0496.下一个更大元素I](https://github.com/youngyangyang04/leetcode/blob/master/problems/0496.下一个更大元素I.md)||中等|**单调栈** 入门题目,但是两个数组还是有点绕的|
359359
|[0501.二叉搜索树中的众数](https://github.com/youngyangyang04/leetcode/blob/master/problems/0501.二叉搜索树中的众数.md)|二叉树|简单|**递归/中序遍历**|
360+
|[0509.斐波那契数](https://github.com/youngyangyang04/leetcode/blob/master/problems/0509.斐波那契数.md)|数组|简单|**递归****动态规划**|
360361
|[0513.找树左下角的值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0513.找树左下角的值.md)|二叉树|中等|**递归****迭代**|
361362
|[0515.在每个树行中找最大值](https://github.com/youngyangyang04/leetcode/blob/master/problems/0515.在每个树行中找最大值.md)|二叉树|简单|**广度优先搜索/队列**|
362363
|[0518.零钱兑换II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0518.零钱兑换II.md)|动态规划|中等|**动态规划** dp里求组合|
@@ -383,6 +384,7 @@
383384
|[0763.划分字母区间](https://github.com/youngyangyang04/leetcode/blob/master/problems/0763.划分字母区间.md)|贪心|中等|**双指针/贪心** 体现贪心尽可能多的思想|
384385
|[0738.单调递增的数字](https://github.com/youngyangyang04/leetcode/blob/master/problems/0738.单调递增的数字.md)|贪心算法|中等|**贪心算法** 思路不错,贪心好题|
385386
|[0739.每日温度](https://github.com/youngyangyang04/leetcode/blob/master/problems/0739.每日温度.md)||中等|**单调栈** 适合单调栈入门|
387+
|[0746.使用最小花费爬楼梯](https://github.com/youngyangyang04/leetcode/blob/master/problems/0746.使用最小花费爬楼梯.md)|动态规划|简单|**动态规划** 入门题目和斐波那契额数列类似|
386388
|[0767.重构字符串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0767.重构字符串.md)|字符串|中等|**字符串** + 排序+一点贪心|
387389
|[0841.钥匙和房间](https://github.com/youngyangyang04/leetcode/blob/master/problems/0841.钥匙和房间.md)|孤岛问题|中等|**bfs****dfs**|
388390
|[0844.比较含退格的字符串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0844.比较含退格的字符串.md)|字符串|简单|******双指针优化** 使用栈的思路但没有必要使用栈|

‎problems/0452.用最少数量的箭引爆气球.md

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,69 @@
1+
<palign='center'>
2+
<imgsrc="https://img-blog.csdnimg.cn/20201215214102642.png"width=400 >
3+
</p>
4+
<palign="center">
5+
<ahref="https://github.com/youngyangyang04/leetcode-master"><imgsrc="https://img.shields.io/badge/Github-leetcode--master-lightgrey"alt=""></a>
6+
<ahref="https://img-blog.csdnimg.cn/20201115103410182.png"><imgsrc="https://img.shields.io/badge/刷题-微信群-green"alt=""></a>
7+
<ahref="https://img-blog.csdnimg.cn/20201210231711160.png"><imgsrc="https://img.shields.io/badge/公众号-代码随想录-brightgreen"alt=""></a>
8+
<ahref="https://space.bilibili.com/525438321"><imgsrc="https://img.shields.io/badge/B站-代码随想录-orange"alt=""></a>
9+
<ahref="https://www.zhihu.com/people/sun-xiu-yang-64"><imgsrc="https://img.shields.io/badge/知乎-代码随想录-blue"alt=""></a>
10+
<ahref="https://www.toutiao.com/c/user/60356270818/#mid=1633692776932365"><imgsrc="https://img.shields.io/badge/头条-代码随想录-red"alt=""></a>
11+
</p>
12+
13+
>思路很直接,但代码并不好写
14+
15+
#452. 用最少数量的箭引爆气球
16+
17+
在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。
18+
19+
一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。
20+
21+
给你一个数组 points ,其中 points[i] =[xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。
22+
23+
24+
示例 1:
25+
输入:points =[[10,16],[2,8],[1,6],[7,12]]
26+
27+
输出:2
28+
解释:对于该样例,x = 6 可以射爆[2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球
29+
30+
示例 2:
31+
输入:points =[[1,2],[3,4],[5,6],[7,8]]
32+
输出:4
33+
34+
示例 3:
35+
输入:points =[[1,2],[2,3],[3,4],[4,5]]
36+
输出:2
37+
38+
示例 4:
39+
输入:points =[[1,2]]
40+
输出:1
41+
42+
示例 5:
43+
输入:points =[[2,3],[2,3]]
44+
输出:1
45+
46+
提示:
47+
48+
* 0 <= points.length <= 10^4
49+
* points[i].length == 2
50+
* -2^31 <= xstart < xend <= 2^31 - 1
151

252
#思路
353

4-
接下来在想一下如何使用最少的弓箭。
54+
如何使用最少的弓箭呢?
555

6-
直觉上来看,貌似只射重叠最多的气球,用的弓箭一定最少,那么有没有当前重叠了三个,我射两个,留下一个和后面的一起射这样弓箭用的更少的情况呢?
56+
直觉上来看,貌似只射重叠最多的气球,用的弓箭一定最少,那么有没有当前重叠了三个气球,我射两个,留下一个和后面的一起射这样弓箭用的更少的情况呢?
757

8-
尝试一下举反例,发现没有这种情况**那么就试一试贪心吧!**
58+
尝试一下举反例,发现没有这种情况
959

10-
算法确定下来了,那么如何模拟气球涉爆的过程呢?是在数组中移除元素还是做标记呢?
60+
那么就试一试贪心吧!局部最优:当气球出现重叠,一起射,所用弓箭最少。全局最优:把所有气球射爆所用弓箭最少。
1161

12-
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。
62+
**算法确定下来了,那么如何模拟气球射爆的过程呢?是在数组中移除元素还是做标记呢?**
1363

14-
但又想一下,如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remove气球,记录一下箭的数量就可以了
64+
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了
1565

16-
>PS:本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!
66+
但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remote气球,只要记录一下箭的数量就可以了。
1767

1868
以上为思考过程,已经确定下来使用贪心了,那么开始解题。
1969

@@ -27,7 +77,7 @@
2777

2878
从前向后遍历遇到重叠的气球了怎么办?
2979

30-
如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭。
80+
**如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭**
3181

3282
以题目示例:[[10,16],[2,8],[1,6],[7,12]]为例,如图:(方便起见,已经排序)
3383

@@ -62,17 +112,34 @@ public:
62112
};
63113
```
64114

65-
时间复杂度O(nlogn)
66-
空间复杂度O(1)
115+
* 时间复杂度O(nlogn),因为有一个快排
116+
* 空间复杂度O(1)
117+
118+
可以看出代码并不复杂。
67119

68120
#注意事项
69121

70122
注意题目中说的是:满足 xstart ≤ x ≤ xend,则该气球会被引爆。那么说明两个气球挨在一起不重叠也可以一起射爆,
71123

72124
所以代码中`if (points[i][0] > points[i - 1][1])` 不能是>=
73125

126+
#总结
127+
128+
这道题目贪心的思路很简单也很直接,就是重复的一起射了,但本题我认为是有难度的。
129+
130+
就算思路都想好了,模拟射气球的过程,很多同学真的要去模拟了,实时把气球从数组中移走,这么写的话就复杂了。
131+
132+
而且寻找重复的气球,寻找重叠气球最小右边界,其实都有代码技巧。
133+
134+
贪心题目有时候就是这样,看起来很简单,思路很直接,但是一写代码就感觉贼复杂无从下手。
135+
136+
这里其实是需要代码功底的,那代码功底怎么练?
137+
138+
**多看多写多总结!**
74139

75-
>**我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
76140

77-
**如果感觉题解对你有帮助,不要吝啬给一个👍吧**
141+
**循序渐进学算法,认准[「代码随想录」](https://img-blog.csdnimg.cn/20200815195519696.png),Carl手把手带你过关斩将**
78142

143+
<palign='center'>
144+
<imgsrc="https://img-blog.csdnimg.cn/20201216002707465.jpg"width=200 >
145+
</p>

‎problems/0509.斐波那契数.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
```
2+
class Solution {
3+
public:
4+
int fib(int N) {
5+
if (N <= 1) return N;
6+
vector<int> dp(N + 1);
7+
dp[0] = 0;
8+
dp[1] = 1;
9+
for (int i = 2; i <= N; i++) {
10+
dp[i] = dp[i - 1] + dp[i - 2];
11+
}
12+
return dp[N];
13+
}
14+
};
15+
```
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
2+
这个爬楼梯的问题和斐波那契数列问题很像。
3+
4+
读完题大家应该知道指定需要动态规划的,贪心是不可能了。
5+
6+
本题在动态规划里相对简单一些,以至于大家可能看个公式就会了,但为了讲清楚思考过程,我按照我总结的动规四步曲来详细讲解:
7+
8+
1. 确定dp数组以及下标的含义
9+
2. 确定递推公式
10+
3. dp数组如何初始化
11+
4. 确定遍历顺序
12+
13+
14+
* 确定dp数组以及下标的含义
15+
16+
使用动态规划,就要有一个数组来记录状态,本题只需要一个一维数组dp[i]就可以了。
17+
18+
dp[i]的定义:第i个台阶所花费的最少体力为dp[i]
19+
20+
**对于dp数组的定义,大家一定要清晰!**
21+
22+
* 确定递推公式
23+
24+
**可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]**
25+
26+
那么究竟是选dp[i-1]还是dp[i-2]呢?
27+
28+
一定是选最小的,所以dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
29+
30+
**注意这里为什么是加cost[i],而不是cost[i-1],cost[i-2]之类的**,因为题目中说了:第i个阶梯对应着一个非负数的体力花费值 cost[i]
31+
32+
* dp数组如何初始化
33+
34+
根据dp数组的定义,dp数组初始化其实是比较难的,因为不可能初始化为第i台阶所花费的最少体力。
35+
36+
那么看一下递归公式,dp[i]由dp[i-1],dp[i-2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。
37+
38+
所以初始化代码为:
39+
40+
```
41+
vector<int> dp(cost.size());
42+
dp[0] = cost[0];
43+
dp[1] = cost[1];
44+
```
45+
46+
* 确定遍历顺序
47+
48+
最后一步,递归公式有了,初始化有了,如何遍历呢?
49+
50+
本题的遍历顺序其实比较简单,简单到很多同学都忽略了思考这一步直接就把代码写出来了。
51+
52+
因为是模拟台阶,而且dp[i]又dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。
53+
54+
但是稍稍有点难度的动态规划,其遍历顺序并不容易确定下来。
55+
56+
例如01背包,都知道两个for循环,一个for遍历物品嵌套一个for遍历背包容量,那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢? 以及在使用一维dp数组的时候遍历背包容量为什么要倒叙呢? 这些都是遍历顺序息息相关。
57+
58+
公众号「代码随想录」后面在讲解动态规划的时候,还会详细说明这些细节,大家可以微信搜一波「代码随想录」,关注后就会发现相见恨晚!
59+
60+
分析完动规四步曲,整体C++代码如下:
61+
62+
```C++
63+
// 版本一
64+
classSolution {
65+
public:
66+
int minCostClimbingStairs(vector<int>& cost) {
67+
vector<int> dp(cost.size());
68+
dp[0] = cost[0];
69+
dp[1] = cost[1];
70+
for (int i = 2; i < cost.size(); i++) {
71+
dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
72+
}
73+
return min(dp[cost.size() - 1], dp[cost.size() - 2]);
74+
}
75+
};
76+
```
77+
78+
* 时间复杂度:O(n)
79+
* 空间复杂度:O(n)
80+
81+
当然还可以优化空间复杂度,因为dp[i]就是由前两位推出来的,那么也不用dp数组了,C++代码如下:
82+
83+
```C++
84+
// 版本二
85+
class Solution {
86+
public:
87+
int minCostClimbingStairs(vector<int>& cost) {
88+
vector<int> dp(cost.size());
89+
int dp0 = cost[0];
90+
int dp1 = cost[1];
91+
for (int i = 2; i < cost.size(); i++) {
92+
dp[i] = min(dp0, dp1) + cost[i];
93+
dp0 = dp1; // 记录一下前两位
94+
dp1 = dp[i];
95+
}
96+
return min(dp[cost.size() - 1], dp[cost.size() - 2]);
97+
}
98+
};
99+
```
100+
101+
* 时间复杂度:O(n)
102+
* 空间复杂度:O(n)
103+
104+
当然我不建议这么写,能写出版本一就可以了,直观简洁!
105+
106+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp