Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1b906da

Browse files
Update
1 parent 6da25b8 commit 1b906da

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+
<p align='center'>
2+
<img src="https://img-blog.csdnimg.cn/20201215214102642.png" width=400 >
3+
</p>
4+
<p align="center">
5+
<a href="https://github.com/youngyangyang04/leetcode-master"><img src="https://img.shields.io/badge/Github-leetcode--master-lightgrey" alt=""></a>
6+
<a href="https://img-blog.csdnimg.cn/20201115103410182.png"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
7+
<a href="https://img-blog.csdnimg.cn/20201210231711160.png"><img src="https://img.shields.io/badge/公众号-代码随想录-brightgreen" alt=""></a>
8+
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
9+
<a href="https://www.zhihu.com/people/sun-xiu-yang-64"><img src="https://img.shields.io/badge/知乎-代码随想录-blue" alt=""></a>
10+
<a href="https://www.toutiao.com/c/user/60356270818/#mid=1633692776932365"><img src="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+
<p align='center'>
144+
<img src="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+
class Solution {
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)