Merge pull request #1956 from Lzzzs/master

贪心算法部分添加视频链接
This commit is contained in:
程序员Carl
2023-03-30 10:56:05 +08:00
committed by GitHub
17 changed files with 437 additions and 356 deletions

View File

@ -4,7 +4,6 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
> 相对于[贪心算法:跳跃游戏](https://mp.weixin.qq.com/s/606_N9j8ACKCODoCbV1lSA)难了不少,做好心里准备!
# 45.跳跃游戏 II
@ -18,13 +17,17 @@
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
* 输入: [2,3,1,1,4]
*: 2
* 解释: 跳到最后一个位置的最小跳跃数是 2。从下标为 0 跳到下标为 1 的位置 1 然后跳 3 步到达数组的最后一个位置。
-: [2,3,1,1,4]
- 输出: 2
- 解释: 跳到最后一个位置的最小跳跃数是 2。从下标为 0 跳到下标为 1 的位置,跳  1  步,然后跳  3  步到达数组的最后一个位置。
说明:
假设你总是可以到达数组的最后一个位置。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法,最少跳几步还得看覆盖范围 | LeetCode 45.跳跃游戏 II](https://www.bilibili.com/video/BV1Y24y1r7XZ),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
@ -46,7 +49,6 @@
如图:
![45.跳跃游戏II](https://code-thinking-1253855093.file.myqcloud.com/pics/20201201232309103.png)
**图中覆盖范围的意义在于,只要红色的区域,最多两步一定可以到!(不用管具体怎么跳,反正一定可以跳到)**
@ -57,8 +59,8 @@
这里还是有个特殊情况需要考虑,当移动下标达到了当前覆盖的最远距离下标时
* 如果当前覆盖最远距离下标不是是集合终点,步数就加一,还需要继续走。
* 如果当前覆盖最远距离下标就是是集合终点,步数不用加一,因为不能再往后走了。
- 如果当前覆盖最远距离下标不是是集合终点,步数就加一,还需要继续走。
- 如果当前覆盖最远距离下标就是是集合终点,步数不用加一,因为不能再往后走了。
C++代码如下:(详细注释)
@ -96,10 +98,10 @@ public:
因为当移动下标指向 nums.size - 2 时:
* 如果移动下标等于当前覆盖最大距离下标, 需要再走一步即ans++),因为最后一步一定是可以到的终点。(题目假设总是可以到达数组的最后一个位置),如图:
- 如果移动下标等于当前覆盖最大距离下标, 需要再走一步(即 ans++),因为最后一步一定是可以到的终点。(题目假设总是可以到达数组的最后一个位置),如图:
![45.跳跃游戏II2](https://code-thinking-1253855093.file.myqcloud.com/pics/20201201232445286.png)
* 如果移动下标不等于当前覆盖最大距离下标,说明当前覆盖最远距离就可以直接达到终点了,不需要再走一步。如图:
- 如果移动下标不等于当前覆盖最大距离下标,说明当前覆盖最远距离就可以直接达到终点了,不需要再走一步。如图:
![45.跳跃游戏II1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201201232338693.png)
@ -137,11 +139,10 @@ public:
理解本题的关键在于:**以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点**,这个范围内最小步数一定可以跳到,不用管具体是怎么跳的,不纠结于一步究竟跳一个单位还是两个单位。
## 其他语言版本
### Java
```Java
// 版本一
class Solution {
@ -230,6 +231,7 @@ class Solution:
step += 1
return step
```
```python
# 动态规划做法
class Solution:
@ -244,7 +246,6 @@ class Solution:
```
### Go
```go
@ -345,7 +346,7 @@ function jump(nums: number[]): number {
curIndex++;
}
return stepNum;
};
}
```
### Scala
@ -427,7 +428,6 @@ impl Solution {
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -4,7 +4,6 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 53. 最大子序和
[力扣题目链接](https://leetcode.cn/problems/maximum-subarray/)
@ -12,17 +11,21 @@
给定一个整数数组 nums 找到一个具有最大和的连续子数组子数组最少包含一个元素返回其最大和。
示例:
* 输入: [-2,1,-3,4,-1,2,1,-5,4]
* 输出: 6
* 解释: 连续子数组 [4,-1,2,1] 的和最大 6。
- 输入: [-2,1,-3,4,-1,2,1,-5,4]
- 输出: 6
- 解释:  连续子数组  [4,-1,2,1] 的和最大,为  6。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法的巧妙需要慢慢体会LeetCode53. 最大子序和](https://www.bilibili.com/video/BV1aY4y1Z7ya),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 暴力解法
暴力解法的思路,第一层 for 就是设置起始位置,第二层 for 循环遍历数组寻找最大值
* 时间复杂度O(n^2)
* 空间复杂度O(1)
- 时间复杂度O(n^2)
- 空间复杂度O(1)
```CPP
class Solution {
@ -56,12 +59,10 @@ public:
**局部最优的情况下,并记录最大的“连续和”,可以推出全局最优**
从代码角度上来讲:遍历 nums从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count只会拖累总和。
**这相当于是暴力解法中的不断调整最大子序和区间的起始位置**
**那有同学问了,区间终止位置不用调整么? 如何才能得到最大“连续和”呢?**
区间的终止位置,其实就是如果 count 取到最大值了,及时记录下来了。例如如下代码:
@ -98,19 +99,17 @@ public:
};
```
* 时间复杂度O(n)
* 空间复杂度O(1)
- 时间复杂度O(n)
- 空间复杂度O(1)
当然题目没有说如果数组为空,应该返回什么,所以数组为空的话返回啥都可以了。
## 常见误区
误区一:
不少同学认为 如果输入用例都是-1或者 都是负数,这个贪心算法跑出来的结果是 0 这是**又一次证明脑洞模拟不靠谱的经典案例**,建议大家把代码运行一下试一试,就知道了,也会理解 为什么 result 要初始化为最小负数了。
误区二:
大家在使用贪心算法求解本题,经常陷入的误区,就是分不清,是遇到 负数就选择起始位置,还是连续和为负选择起始位置。
@ -123,8 +122,6 @@ public:
其实并不会,因为还有一个变量 result 一直在更新 最大的连续和只要有更大的连续和出现result 就更新了,那么 result 已经把 4 更新了,后面 连续和变成 3也不会对最后结果有影响。
## 动态规划
当然本题还可以用动态规划来做,当前[「代码随想录」](https://img-blog.csdnimg.cn/20201124161234338.png)主要讲解贪心系列,后续到动态规划系列的时候会详细讲解本题的 dp 方法。
@ -148,8 +145,8 @@ public:
};
```
* 时间复杂度O(n)
* 空间复杂度O(n)
- 时间复杂度O(n)
- 空间复杂度O(n)
## 总结
@ -159,8 +156,8 @@ public:
## 其他语言版本
### Java
```java
class Solution {
public int maxSubArray(int[] nums) {
@ -201,6 +198,7 @@ class Solution {
```
### Python
```python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
@ -233,6 +231,7 @@ func maxSubArray(nums []int) int {
```
### Rust
```rust
pub fn max_sub_array(nums: Vec<i32>) -> i32 {
let mut max_sum = i32::MIN;
@ -247,6 +246,7 @@ pub fn max_sub_array(nums: Vec<i32>) -> i32 {
```
### Javascript:
```Javascript
var maxSubArray = function(nums) {
let result = -Infinity
@ -264,9 +264,10 @@ var maxSubArray = function(nums) {
};
```
### C:
贪心:
```c
int maxSubArray(int* nums, int numsSize){
int maxVal = INT_MIN;
@ -286,6 +287,7 @@ int maxSubArray(int* nums, int numsSize){
```
动态规划:
```c
/**
* 解题思路:动态规划:
@ -332,7 +334,7 @@ function maxSubArray(nums: number[]): number {
if (curSum < 0) curSum = 0;
}
return resMax;
};
}
```
**动态规划**
@ -350,7 +352,7 @@ function maxSubArray(nums: number[]): number {
resMax = Math.max(resMax, dp[i]);
}
return resMax;
};
}
```
### Scala

View File

@ -4,7 +4,6 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 55. 跳跃游戏
[力扣题目链接](https://leetcode.cn/problems/jump-game/)
@ -16,15 +15,20 @@
判断你是否能够到达最后一个位置。
示例  1:
* 输入: [2,3,1,1,4]
*: true
* 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
-: [2,3,1,1,4]
- 输出: true
- 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例  2:
* 输入: [3,2,1,0,4]
* 输出: false
* 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 所以你永远不可能到达最后一个位置。
- 输入: [3,2,1,0,4]
- 输出: false
- 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 所以你永远不可能到达最后一个位置。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法,怎么跳跃不重要,关键在覆盖范围 | LeetCode55.跳跃游戏](https://www.bilibili.com/video/BV1VG4y1X7kB),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
@ -46,7 +50,6 @@
如图:
![55.跳跃游戏](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124154758229-20230310135019977.png)
i 每次移动只能在 cover 的范围内移动每移动一个元素cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。
@ -71,6 +74,7 @@ public:
}
};
```
## 总结
这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。
@ -83,8 +87,8 @@ public:
## 其他语言版本
### Java
```Java
class Solution {
public boolean canJump(int[] nums) {
@ -106,6 +110,7 @@ class Solution {
```
### Python
```python
class Solution:
def canJump(self, nums: List[int]) -> bool:
@ -156,8 +161,6 @@ func max(a, b int ) int {
}
```
### Javascript
```Javascript
@ -196,6 +199,7 @@ impl Solution {
```
### C
```c
#define max(a, b) (((a) > (b)) ? (a) : (b))
@ -217,7 +221,6 @@ bool canJump(int* nums, int numsSize){
}
```
### TypeScript
```typescript
@ -230,10 +233,11 @@ function canJump(nums: number[]): boolean {
cur++;
}
return false;
};
}
```
### Scala
```scala
object Solution {
def canJump(nums: Array[Int]): Boolean = {
@ -250,7 +254,6 @@ object Solution {
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -22,6 +22,9 @@
* 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
* 注意输入类型已于2019年4月15日更改。 请重置默认代码定义以获取新方法签名。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法合并区间有细节LeetCode56.合并区间](https://www.bilibili.com/video/BV1wx4y157nD),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -4,7 +4,6 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 122.买卖股票的最佳时机 II
[力扣题目链接](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/)
@ -15,32 +14,39 @@
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
* 输入: [7,1,5,3,6,4]
*: 7
* 解释: 在第 2 天(股票价格 = 1的时候买入在第 3 天(股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后在第 4 天(股票价格 = 3的时候买入在第 5 天(股票价格 = 6的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
-: [7,1,5,3,6,4]
- 输出: 7
- 解释: 在第 2 天(股票价格 = 1的时候买入在第 3 天(股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后在第 4 天(股票价格 = 3的时候买入在第 5 天(股票价格 = 6的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
* 输入: [1,2,3,4,5]
*: 4
* 解释: 在第 1 天(股票价格 = 1的时候买入在第 5 天 (股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
-: [1,2,3,4,5]
- 输出: 4
- 解释: 在第 1 天(股票价格 = 1的时候买入在第 5 天 (股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例  3:
* 输入: [7,6,4,3,1]
*: 0
* 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
-: [7,6,4,3,1]
- 输出: 0
- 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
* 1 <= prices.length <= 3 * 10 ^ 4
* 0 <= prices[i] <= 10 ^ 4
- 1 <= prices.length <= 3 \* 10 ^ 4
- 0 <= prices[i] <= 10 ^ 4
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法也能解决股票问题LeetCode122.买卖股票最佳时机 II](https://www.bilibili.com/video/BV1ev4y1C7na),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
本题首先要清楚两点:
* 只有一只股票!
* 当前只有买股票或者卖股票的操作
- 只有一只股票!
- 当前只有买股票或者卖股票的操作
想获得利润至少要两天为一个交易单元。
@ -62,7 +68,6 @@
如图:
![122.买卖股票的最佳时机II](https://code-thinking-1253855093.file.myqcloud.com/pics/2020112917480858-20230310134659477.png)
一些同学陷入:第一天怎么就没有利润呢,第一天到底算不算的困惑中。
@ -92,8 +97,8 @@ public:
};
```
* 时间复杂度O(n)
* 空间复杂度O(1)
- 时间复杂度O(n)
- 空间复杂度O(1)
### 动态规划
@ -119,8 +124,8 @@ public:
};
```
* 时间复杂度:$O(n)$
* 空间复杂度:$O(n)$
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
## 总结
@ -137,6 +142,7 @@ public:
### Java:
贪心:
```java
// 贪心思路
class Solution {
@ -151,6 +157,7 @@ class Solution {
```
动态规划:
```java
class Solution { // 动态规划
public int maxProfit(int[] prices) {
@ -173,7 +180,9 @@ class Solution { // 动态规划
```
### Python:
贪心:
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
@ -184,6 +193,7 @@ class Solution:
```
动态规划:
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
@ -200,6 +210,7 @@ class Solution:
### Go:
贪心算法
```go
func maxProfit(prices []int) int {
var sum int
@ -212,7 +223,9 @@ func maxProfit(prices []int) int {
return sum
}
```
动态规划
```go
func maxProfit(prices []int) int {
dp := make([][]int, len(prices))
@ -239,6 +252,7 @@ func max(a, b int) int {
### Javascript:
贪心
```Javascript
var maxProfit = function(prices) {
let result = 0
@ -250,6 +264,7 @@ var maxProfit = function(prices) {
```
动态规划
```javascript
const maxProfit = (prices) => {
let dp = Array.from(Array(prices.length), () => Array(2).fill(0));
@ -283,7 +298,7 @@ function maxProfit(prices: number[]): number {
resProfit += Math.max(prices[i] - prices[i - 1], 0);
}
return resProfit;
};
}
```
动态规划
@ -304,6 +319,7 @@ function maxProfit(prices: number[]): number {
### Rust
贪心:
```Rust
impl Solution {
fn max(a: i32, b: i32) -> i32 {
@ -320,6 +336,7 @@ impl Solution {
```
动态规划:
```Rust
impl Solution {
fn max(a: i32, b: i32) -> i32 {
@ -339,7 +356,9 @@ impl Solution {
```
### C:
贪心:
```c
int maxProfit(int* prices, int pricesSize){
int result = 0;
@ -355,6 +374,7 @@ int maxProfit(int* prices, int pricesSize){
```
动态规划:
```c
#define max(a, b) (((a) > (b)) ? (a) : (b))
@ -379,6 +399,7 @@ int maxProfit(int* prices, int pricesSize){
### Scala
贪心:
```scala
object Solution {
def maxProfit(prices: Array[Int]): Int = {

View File

@ -45,6 +45,10 @@
* 解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油。开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油。开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油。你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。因此,无论怎样,你都不可能绕环路行驶一周。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法得这么加油才能跑完全程LeetCode 134.加油站](https://www.bilibili.com/video/BV1jA411r7WX),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 暴力方法

View File

@ -28,6 +28,10 @@
* 输出: 4
* 解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法两者兼顾很容易顾此失彼LeetCode135.分发糖果](https://www.bilibili.com/video/BV1ev4y1r7wN),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -4,7 +4,6 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
> 本周讲解了[贪心理论基础](https://programmercarl.com/贪心算法理论基础.html),以及第一道贪心的题目:[贪心算法:分发饼干](https://programmercarl.com/0455.分发饼干.html),可能会给大家一种贪心算法比较简单的错觉,好了,接下来几天的题目难度要上来了,哈哈。
# 376. 摆动序列
@ -18,18 +17,25 @@
给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。
示例 1:
* 输入: [1,7,4,9,2,5]
*: 6
* 解释: 整个序列均为摆动序列。
-: [1,7,4,9,2,5]
- 输出: 6
- 解释: 整个序列均为摆动序列。
示例 2:
* 输入: [1,17,5,10,13,15,10,5,16,8]
*: 7
* 解释: 这个序列包含几个长度为 7 摆动序列,其中一个可为[1,17,10,13,10,16,8]。
-: [1,17,5,10,13,15,10,5,16,8]
- 输出: 7
- 解释: 这个序列包含几个长度为 7 摆动序列,其中一个可为[1,17,10,13,10,16,8]。
示例 3:
* 输入: [1,2,3,4,5,6,7,8,9]
*: 2
-: [1,2,3,4,5,6,7,8,9]
- 输出: 2
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法,寻找摆动有细节!| LeetCode376.摆动序列](https://www.bilibili.com/video/BV17M411b7NS),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路 1贪心解法
@ -81,10 +87,8 @@
所以我们记录峰值的条件应该是: `(preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)`,为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。
### 情况二:数组首尾两端
所以本题统计峰值的时候,数组最左面和最右面如果统计呢?
题目中说了,如果只有两个不同的元素,那摆动序列也是 2。
@ -130,8 +134,9 @@ public:
}
};
```
* 时间复杂度O(n)
* 空间复杂度O(1)
-间复杂度O(n)
- 空间复杂度O(1)
此时大家是不是发现 以上代码提交也不能通过本题?
@ -188,13 +193,13 @@ public:
很容易可以发现,对于我们当前考虑的这个数,要么是作为山峰(即 nums[i] > nums[i-1]),要么是作为山谷(即 nums[i] < nums[i - 1])。
* 设dp状态`dp[i][0]`表示考虑前i个数第i个数作为山峰的摆动子序列的最长长度
* 设dp状态`dp[i][1]`表示考虑前i个数第i个数作为山谷的摆动子序列的最长长度
- dp 状态`dp[i][0]`表示考虑前 i 个数 i 个数作为山峰的摆动子序列的最长长度
- dp 状态`dp[i][1]`表示考虑前 i 个数 i 个数作为山谷的摆动子序列的最长长度
则转移方程为
* `dp[i][0] = max(dp[i][0], dp[j][1] + 1)`,其中`0 < j < i`且`nums[j] < nums[i]`表示将nums[i]接到前面某个山谷后面,作为山峰。
* `dp[i][1] = max(dp[i][1], dp[j][0] + 1)`,其中`0 < j < i`且`nums[j] > nums[i]`表示将nums[i]接到前面某个山峰后面,作为山谷。
- `dp[i][0] = max(dp[i][0], dp[j][1] + 1)`其中`0 < j < i``nums[j] < nums[i]`表示将 nums[i]接到前面某个山谷后面作为山峰
- `dp[i][1] = max(dp[i][1], dp[j][0] + 1)`其中`0 < j < i``nums[j] > nums[i]`表示将 nums[i]接到前面某个山峰后面作为山谷
初始状态
@ -223,28 +228,25 @@ public:
};
```
* 时间复杂度O(n^2)
* 空间复杂度O(n)
- 时间复杂度O(n^2)
- 空间复杂度O(n)
**进阶**
可以用两棵线段树来维护区间的最大值
* 每次更新`dp[i][0]`,则在`tree1`的`nums[i]`位置值更新为`dp[i][0]`
* 每次更新`dp[i][1]`,则在`tree2`的`nums[i]`位置值更新为`dp[i][1]`
* 则dp转移方程中就没有必要j从0遍历到i-1可以直接在线段树中查询指定区间的值即可
- 每次更新`dp[i][0]`则在`tree1``nums[i]`位置值更新为`dp[i][0]`
- 每次更新`dp[i][1]`则在`tree2``nums[i]`位置值更新为`dp[i][1]`
- dp 转移方程中就没有必要 j 0 遍历到 i-1可以直接在线段树中查询指定区间的值即可
时间复杂度O(nlog n)
空间复杂度O(n)
## 其他语言版本
### Java
```Java
class Solution {
public int wiggleMaxLength(int[] nums) {
@ -270,6 +272,7 @@ class Solution {
}
}
```
```java
// DP
class Solution {
@ -360,6 +363,7 @@ class Solution:
### Go
**贪心**
```go
func wiggleMaxLength(nums []int) int {
n := len(nums)
@ -383,6 +387,7 @@ func wiggleMaxLength(nums []int) int {
```
**动态规划**
```go
func wiggleMaxLength(nums []int) int {
n := len(nums)
@ -420,7 +425,9 @@ func max(a, b int) int {
```
### Javascript
**贪心**
```Javascript
var wiggleMaxLength = function(nums) {
if(nums.length <= 1) return nums.length
@ -437,7 +444,9 @@ var wiggleMaxLength = function(nums) {
return result
};
```
**动态规划**
```Javascript
var wiggleMaxLength = function(nums) {
if (nums.length === 1) return 1;
@ -458,7 +467,9 @@ var wiggleMaxLength = function(nums) {
```
### Rust
**贪心**
```Rust
impl Solution {
pub fn wiggle_max_length(nums: Vec<i32>) -> i32 {
@ -504,6 +515,7 @@ impl Solution {
```
### C
**贪心**
```c
@ -568,8 +580,6 @@ int wiggleMaxLength(int* nums, int numsSize){
}
```
### TypeScript
**贪心**
@ -583,16 +593,13 @@ function wiggleMaxLength(nums: number[]): number {
let count: number = 1;
for (let i = 1; i < length; i++) {
curDiff = nums[i] - nums[i - 1];
if (
(preDiff <= 0 && curDiff > 0) ||
(preDiff >= 0 && curDiff < 0)
) {
if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) {
preDiff = curDiff;
count++;
}
}
return count;
};
}
```
**动态规划**
@ -601,7 +608,7 @@ function wiggleMaxLength(nums: number[]): number {
function wiggleMaxLength(nums: number[]): number {
const length: number = nums.length;
if (length <= 1) return length;
const dp: number[][] = new Array(length).fill(0).map(_ => []);
const dp: number[][] = new Array(length).fill(0).map((_) => []);
dp[0][0] = 1; // 第一个数作为波峰
dp[0][1] = 1; // 第一个数作为波谷
for (let i = 1; i < length; i++) {
@ -615,7 +622,7 @@ function wiggleMaxLength(nums: number[]): number {
}
}
return Math.max(dp[length - 1][0], dp[length - 1][1]);
};
}
```
### Scala

View File

@ -37,6 +37,10 @@
题目数据确保队列可以被重建
# 视频讲解
**代码随想录算法视频公开课[贪心算法,不要两边一起贪,会顾此失彼 | LeetCode406.根据身高重建队列](https://www.bilibili.com/video/BV1EA411675Y)相信结合视频在看本篇题解更有助于大家对本题的理解**。
## 思路
本题有两个维度h和k看到这种题目一定要想如何确定一个维度然后再按照另一个维度重新排列

View File

@ -30,6 +30,10 @@
* 输出: 0
* 解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法,依然是判断重叠区间 | LeetCode435.无重叠区间](https://www.bilibili.com/video/BV1A14y1c7E1),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
**相信很多同学看到这道题目都冥冥之中感觉要排序,但是究竟是按照右边界排序,还是按照左边界排序呢?**

View File

@ -42,6 +42,10 @@
* points[i].length == 2
* -2^31 <= xstart < xend <= 2^31 - 1
# 视频讲解
**代码随想录算法视频公开课[贪心算法,判断重叠区间问题 | LeetCode452.用最少数量的箭引爆气球](https://www.bilibili.com/video/BV1SA41167xe)相信结合视频在看本篇题解更有助于大家对本题的理解**。
## 思路
如何使用最少的弓箭呢

View File

@ -4,7 +4,6 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 455.分发饼干
[力扣题目链接](https://leetcode.cn/problems/assign-cookies/)
@ -14,21 +13,26 @@
对每个孩子 i都有一个胃口值  g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
示例  1:
* 输入: g = [1,2,3], s = [1,1]
*: 1
-: g = [1,2,3], s = [1,1]
- 输出: 1
解释:你有三个孩子和两块小饼干3 个孩子的胃口值分别是1,2,3。虽然你有两块小饼干由于他们的尺寸都是 1你只能让胃口值是 1 的孩子满足。所以你应该输出 1。
示例  2:
* 输入: g = [1,2], s = [1,2,3]
* 输出: 2
* 解释:你有两个孩子和三块小饼干2个孩子的胃口值分别是1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出2.
- 输入: g = [1,2], s = [1,2,3]
- 输出: 2
- 解释:你有两个孩子和三块小饼干2 个孩子的胃口值分别是 1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出 2.
提示:
* 1 <= g.length <= 3 * 10^4
* 0 <= s.length <= 3 * 10^4
* 1 <= g[i], s[j] <= 2^31 - 1
- 1 <= g.length <= 3 \* 10^4
- 0 <= s.length <= 3 \* 10^4
- 1 <= g[i], s[j] <= 2^31 - 1
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法,你想先喂哪个小孩?| LeetCode455.分发饼干](https://www.bilibili.com/video/BV1MM411b7cq),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
@ -46,10 +50,8 @@
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230203105634.png)
这个例子可以看出饼干 9 只有喂给胃口为 7 的小孩,这样才是整体最优解,并想不出反例,那么就可以撸代码了。
C++代码整体如下:
```CPP
@ -78,7 +80,6 @@ public:
有的同学看到要遍历两个数组,就想到用两个 for 循环,那样逻辑其实就复杂了。
### 注意事项
注意版本一的代码中,可以看出来,是先遍历的胃口,在遍历的饼干,那么可不可以 先遍历 饼干,在遍历胃口呢?
@ -95,7 +96,6 @@ if 里的 index 指向 胃口 10 for里的i指向饼干9因为 饼干9 满
所以 一定要 for 控制 胃口,里面的 if 控制饼干。
### 其他思路
**也可以换一个思路,小饼干先喂饱小胃口**
@ -131,8 +131,8 @@ public:
## 其他语言版本
### Java
```java
class Solution {
// 思路1优先考虑饼干小饼干先喂饱小胃口
@ -151,6 +151,7 @@ class Solution {
}
}
```
```java
class Solution {
// 思路2优先考虑胃口先喂饱大胃口
@ -172,6 +173,7 @@ class Solution {
```
### Python
```python
class Solution:
# 思路1优先考虑小胃口
@ -184,6 +186,7 @@ class Solution:
res += 1
return res
```
```python
class Solution:
# 思路2优先考虑大胃口
@ -199,6 +202,7 @@ class Solution:
```
### Go
```golang
//排序后,局部最优
func findContentChildren(g []int, s []int) int {
@ -218,6 +222,7 @@ func findContentChildren(g []int, s []int) int {
```
### Rust
```rust
pub fn find_content_children(mut children: Vec<i32>, mut cookie: Vec<i32>) -> i32 {
children.sort();
@ -236,21 +241,21 @@ pub fn find_content_children(mut children: Vec<i32>, mut cookie: Vec<i32>) -> i3
```
### Javascript
```js
var findContentChildren = function (g, s) {
g = g.sort((a, b) => a - b)
s = s.sort((a, b) => a - b)
let result = 0
let index = s.length - 1
g = g.sort((a, b) => a - b);
s = s.sort((a, b) => a - b);
let result = 0;
let index = s.length - 1;
for (let i = g.length - 1; i >= 0; i--) {
if (index >= 0 && s[index] >= g[i]) {
result++
index--
result++;
index--;
}
}
return result
return result;
};
```
### TypeScript
@ -273,7 +278,7 @@ function findContentChildren(g: number[], s: number[]): number {
curChild--;
}
return resCount;
};
}
```
```typescript
@ -292,7 +297,7 @@ function findContentChildren(g: number[], s: number[]): number {
curCookie++;
}
return curChild;
};
}
```
### C

View File

@ -26,6 +26,10 @@
说明: N 是在 [0, 10^9] 范围内的一个整数。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法思路不难想但代码不好写LeetCode:738.单调自增的数字](https://www.bilibili.com/video/BV1Kv4y1x7tP),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 暴力解法

View File

@ -24,6 +24,10 @@
* S的长度在[1, 500]之间。
* S只包含小写字母 'a' 到 'z' 。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法,寻找最远的出现位置! LeetCode763.划分字母区间](https://www.bilibili.com/video/BV18G4y1K7d5),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
一想到分割字符串就想到了回溯,但本题其实不用回溯去暴力搜索。

View File

@ -50,6 +50,10 @@
* 0 <= bills.length <= 10000
* bills[i] 不是 5 就是 10 或是 20 
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法看上去复杂其实逻辑都是固定的LeetCode860.柠檬水找零](https://www.bilibili.com/video/BV12x4y1j7DD),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
这是前几天的leetcode每日一题感觉不错给大家讲一下。

View File

@ -38,6 +38,10 @@
* 给定树的节点数的范围是 [1, 1000]。
* 每个节点的值都是 0。
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法,二叉树与贪心的结合,有点难...... LeetCode:968.监督二叉树](https://www.bilibili.com/video/BV1SA411U75i),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -34,6 +34,10 @@
* 1 <= K <= 10000
* -100 <= A[i] <= 100
# 视频讲解
**《代码随想录》算法视频公开课:[贪心算法这不就是常识还能叫贪心LeetCode1005.K次取反后最大化的数组和](https://www.bilibili.com/video/BV138411G7LY),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
## 思路
本题思路其实比较好想了,如何可以让数组和最大呢?