mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-12 21:50:49 +08:00
Merge pull request #1820 from juguagua/leetcode-modify-the-code-of-the-greedy
更新贪心部分:至 “用最少数量的箭引爆气球”
This commit is contained in:
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
贪心的思路,局部最优:当前可移动距离尽可能多走,如果还没到终点,步数再加一。整体最优:一步尽可能多走,从而达到最小步数。
|
贪心的思路,局部最优:当前可移动距离尽可能多走,如果还没到终点,步数再加一。整体最优:一步尽可能多走,从而达到最小步数。
|
||||||
|
|
||||||
思路虽然是这样,但在写代码的时候还不能真的就能跳多远跳远,那样就不知道下一步最远能跳到哪里了。
|
思路虽然是这样,但在写代码的时候还不能真的能跳多远就跳多远,那样就不知道下一步最远能跳到哪里了。
|
||||||
|
|
||||||
**所以真正解题的时候,要从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最小步数!**
|
**所以真正解题的时候,要从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最小步数!**
|
||||||
|
|
||||||
@ -234,31 +234,6 @@ class Solution:
|
|||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
```Go
|
|
||||||
func jump(nums []int) int {
|
|
||||||
dp := make([]int, len(nums))
|
|
||||||
dp[0] = 0//初始第一格跳跃数一定为0
|
|
||||||
|
|
||||||
for i := 1; i < len(nums); i++ {
|
|
||||||
dp[i] = i
|
|
||||||
for j := 0; j < i; j++ {
|
|
||||||
if nums[j] + j >= i {//nums[j]为起点,j为往右跳的覆盖范围,这行表示从j能跳到i
|
|
||||||
dp[i] = min(dp[j] + 1, dp[i])//更新最小能到i的跳跃次数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dp[len(nums)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func min(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return a
|
|
||||||
} else {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// 贪心版本一
|
// 贪心版本一
|
||||||
func jump(nums []int) int {
|
func jump(nums []int) int {
|
||||||
@ -320,8 +295,6 @@ func max(a, b int) int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
|
|
||||||
```Javascript
|
```Javascript
|
||||||
|
@ -176,13 +176,13 @@ public:
|
|||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:$O(n)$
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:$O(1)$
|
||||||
|
|
||||||
**说这种解法为贪心算法,才是是有理有据的,因为全局最优解是根据局部最优推导出来的**。
|
**说这种解法为贪心算法,才是有理有据的,因为全局最优解是根据局部最优推导出来的**。
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
对于本题首先给出了暴力解法,暴力解法模拟跑一圈的过程其实比较考验代码技巧的,要对while使用的很熟练。
|
对于本题首先给出了暴力解法,暴力解法模拟跑一圈的过程其实比较考验代码技巧的,要对while使用的很熟练。
|
||||||
|
|
||||||
然后给出了两种贪心算法,对于第一种贪心方法,其实我认为就是一种直接从全局选取最优的模拟操作,思路还是好巧妙的,值得学习一下。
|
然后给出了两种贪心算法,对于第一种贪心方法,其实我认为就是一种直接从全局选取最优的模拟操作,思路还是很巧妙的,值得学习一下。
|
||||||
|
|
||||||
对于第二种贪心方法,才真正体现出贪心的精髓,用局部最优可以推出全局最优,进而求得起始位置。
|
对于第二种贪心方法,才真正体现出贪心的精髓,用局部最优可以推出全局最优,进而求得起始位置。
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ for (int i = 1; i < ratings.size(); i++) {
|
|||||||
|
|
||||||
如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。
|
如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。
|
||||||
|
|
||||||
那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量即大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
|
那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
|
||||||
|
|
||||||
局部最优可以推出全局最优。
|
局部最优可以推出全局最优。
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
```golang
|
```go
|
||||||
func candy(ratings []int) int {
|
func candy(ratings []int) int {
|
||||||
/**先确定一边,再确定另外一边
|
/**先确定一边,再确定另外一边
|
||||||
1.先从左到右,当右边的大于左边的就加1
|
1.先从左到右,当右边的大于左边的就加1
|
||||||
@ -210,25 +210,6 @@ func findMax(num1 int ,num2 int) int{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Rust
|
|
||||||
```rust
|
|
||||||
pub fn candy(ratings: Vec<i32>) -> i32 {
|
|
||||||
let mut candies = vec![1i32; ratings.len()];
|
|
||||||
for i in 1..ratings.len() {
|
|
||||||
if ratings[i - 1] < ratings[i] {
|
|
||||||
candies[i] = candies[i - 1] + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in (0..ratings.len()-1).rev() {
|
|
||||||
if ratings[i] > ratings[i + 1] {
|
|
||||||
candies[i] = candies[i].max(candies[i + 1] + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
candies.iter().sum()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Javascript:
|
### Javascript:
|
||||||
```Javascript
|
```Javascript
|
||||||
var candy = function(ratings) {
|
var candy = function(ratings) {
|
||||||
@ -255,6 +236,25 @@ var candy = function(ratings) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Rust
|
||||||
|
```rust
|
||||||
|
pub fn candy(ratings: Vec<i32>) -> i32 {
|
||||||
|
let mut candies = vec![1i32; ratings.len()];
|
||||||
|
for i in 1..ratings.len() {
|
||||||
|
if ratings[i - 1] < ratings[i] {
|
||||||
|
candies[i] = candies[i - 1] + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in (0..ratings.len()-1).rev() {
|
||||||
|
if ratings[i] > ratings[i + 1] {
|
||||||
|
candies[i] = candies[i].max(candies[i + 1] + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
candies.iter().sum()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### C
|
### C
|
||||||
```c
|
```c
|
||||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
## 思路
|
## 思路
|
||||||
|
|
||||||
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后在按照另一个维度重新排列。
|
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后再按照另一个维度重新排列。
|
||||||
|
|
||||||
其实如果大家认真做了[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html),就会发现和此题有点点的像。
|
其实如果大家认真做了[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html),就会发现和此题有点点的像。
|
||||||
|
|
||||||
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
**如果两个维度一起考虑一定会顾此失彼**。
|
**如果两个维度一起考虑一定会顾此失彼**。
|
||||||
|
|
||||||
对于本题相信大家困惑的点是先确定k还是先确定h呢,也就是究竟先按h排序呢,还先按照k排序呢?
|
对于本题相信大家困惑的点是先确定k还是先确定h呢,也就是究竟先按h排序呢,还是先按照k排序呢?
|
||||||
|
|
||||||
如果按照k来从小到大排序,排完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
|
如果按照k来从小到大排序,排完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
|
||||||
|
|
||||||
@ -225,28 +225,26 @@ func reconstructQueue(people [][]int) [][]int {
|
|||||||
// 先将身高从大到小排序,确定最大个子的相对位置
|
// 先将身高从大到小排序,确定最大个子的相对位置
|
||||||
sort.Slice(people, func(i, j int) bool {
|
sort.Slice(people, func(i, j int) bool {
|
||||||
if people[i][0] == people[j][0] {
|
if people[i][0] == people[j][0] {
|
||||||
return people[i][1]<people[j][1]//这个才是当身高相同时,将K按照从小到大排序
|
return people[i][1] < people[j][1] // 当身高相同时,将K按照从小到大排序
|
||||||
}
|
}
|
||||||
return people[i][0]>people[j][0]//这个只是确保身高按照由大到小的顺序来排,并不确定K是按照从小到大排序的
|
return people[i][0] > people[j][0] // 身高按照由大到小的顺序来排
|
||||||
})
|
})
|
||||||
|
|
||||||
// 再按照K进行插入排序,优先插入K小的
|
// 再按照K进行插入排序,优先插入K小的
|
||||||
result := make([][]int, 0)
|
for i, p := range people {
|
||||||
for _, info := range people {
|
copy(people[p[1]+1 : i+1], people[p[1] : i+1]) // 空出一个位置
|
||||||
result = append(result, info)
|
people[p[1]] = p
|
||||||
copy(result[info[1] +1:], result[info[1]:])//将插入位置之后的元素后移动一位(意思是腾出空间)
|
|
||||||
result[info[1]] = info//将插入元素位置插入元素
|
|
||||||
}
|
}
|
||||||
return result
|
return people
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
```go
|
```go
|
||||||
//链表法
|
// 链表实现
|
||||||
func reconstructQueue(people [][]int) [][]int {
|
func reconstructQueue(people [][]int) [][]int {
|
||||||
sort.Slice(people,func (i,j int) bool {
|
sort.Slice(people,func (i,j int) bool {
|
||||||
if people[i][0] == people[j][0] {
|
if people[i][0] == people[j][0] {
|
||||||
return people[i][1] < people[j][1] //当身高相同时,将K按照从小到大排序
|
return people[i][1] < people[j][1] //当身高相同时,将K按照从小到大排序
|
||||||
}
|
}
|
||||||
//先将身高从大到小排序,确定最大个子的相对位置
|
|
||||||
return people[i][0] > people[j][0]
|
return people[i][0] > people[j][0]
|
||||||
})
|
})
|
||||||
l := list.New() //创建链表
|
l := list.New() //创建链表
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
|
|
||||||
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。
|
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。
|
||||||
|
|
||||||
但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remote气球,只要记录一下箭的数量就可以了。
|
但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remove气球,只要记录一下箭的数量就可以了。
|
||||||
|
|
||||||
以上为思考过程,已经确定下来使用贪心了,那么开始解题。
|
以上为思考过程,已经确定下来使用贪心了,那么开始解题。
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
```golang
|
```go
|
||||||
func findMinArrowShots(points [][]int) int {
|
func findMinArrowShots(points [][]int) int {
|
||||||
var res int = 1 //弓箭数
|
var res int = 1 //弓箭数
|
||||||
//先按照第一位排序
|
//先按照第一位排序
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
这是前几天的leetcode每日一题,感觉不错,给大家讲一下。
|
这是前几天的leetcode每日一题,感觉不错,给大家讲一下。
|
||||||
|
|
||||||
这道题目刚一看,可能会有点懵,这要怎么找零才能保证完整全部账单的找零呢?
|
这道题目刚一看,可能会有点懵,这要怎么找零才能保证完成全部账单的找零呢?
|
||||||
|
|
||||||
**但仔细一琢磨就会发现,可供我们做判断的空间非常少!**
|
**但仔细一琢磨就会发现,可供我们做判断的空间非常少!**
|
||||||
|
|
||||||
@ -179,37 +179,22 @@ class Solution:
|
|||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
```golang
|
```go
|
||||||
func lemonadeChange(bills []int) bool {
|
func lemonadeChange(bills []int) bool {
|
||||||
//left表示还剩多少 下标0位5元的个数 ,下标1为10元的个数
|
ten, five := 0, 0
|
||||||
left:=[2]int{0,0}
|
|
||||||
//第一个元素不为5,直接退出
|
|
||||||
if bills[0]!=5{
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i := 0; i < len(bills); i++ {
|
for i := 0; i < len(bills); i++ {
|
||||||
//先统计5元和10元的个数
|
|
||||||
if bills[i] == 5 {
|
if bills[i] == 5 {
|
||||||
left[0]+=1
|
five++
|
||||||
}
|
} else if bills[i] == 10 {
|
||||||
if bills[i]==10{
|
if five == 0 {
|
||||||
left[1]+=1
|
|
||||||
}
|
|
||||||
//接着处理找零的
|
|
||||||
tmp:=bills[i]-5
|
|
||||||
if tmp==5{
|
|
||||||
if left[0]>0{
|
|
||||||
left[0]-=1
|
|
||||||
}else {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
ten++; five--
|
||||||
if tmp==15{
|
} else {
|
||||||
if left[1]>0&&left[0]>0{
|
if ten >= 1 && five >= 1 {
|
||||||
left[0]-=1
|
ten--; five--
|
||||||
left[1]-=1
|
} else if five >= 3 {
|
||||||
}else if left[1]==0&&left[0]>2{
|
five -= 3
|
||||||
left[0]-=3
|
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user