mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-11 21:10:58 +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,63 +172,44 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
```golang
|
```go
|
||||||
func candy(ratings []int) int {
|
func candy(ratings []int) int {
|
||||||
/**先确定一边,再确定另外一边
|
/**先确定一边,再确定另外一边
|
||||||
1.先从左到右,当右边的大于左边的就加1
|
1.先从左到右,当右边的大于左边的就加1
|
||||||
2.再从右到左,当左边的大于右边的就再加1
|
2.再从右到左,当左边的大于右边的就再加1
|
||||||
**/
|
**/
|
||||||
need:=make([]int,len(ratings))
|
need := make([]int, len(ratings))
|
||||||
sum:=0
|
sum := 0
|
||||||
//初始化(每个人至少一个糖果)
|
// 初始化(每个人至少一个糖果)
|
||||||
for i:=0;i<len(ratings);i++{
|
for i := 0; i < len(ratings); i++ {
|
||||||
need[i]=1
|
need[i] = 1
|
||||||
}
|
}
|
||||||
//1.先从左到右,当右边的大于左边的就加1
|
// 1.先从左到右,当右边的大于左边的就加1
|
||||||
for i:=0;i<len(ratings)-1;i++{
|
for i := 0; i < len(ratings) - 1; i++ {
|
||||||
if ratings[i]<ratings[i+1]{
|
if ratings[i] < ratings[i+1] {
|
||||||
need[i+1]=need[i]+1
|
need[i+1] = need[i] + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//2.再从右到左,当左边的大于右边的就右边加1,但要花费糖果最少,所以需要做下判断
|
// 2.再从右到左,当左边的大于右边的就右边加1,但要花费糖果最少,所以需要做下判断
|
||||||
for i:=len(ratings)-1;i>0;i--{
|
for i := len(ratings)-1; i > 0; i-- {
|
||||||
if ratings[i-1]>ratings[i]{
|
if ratings[i-1] > ratings[i] {
|
||||||
need[i-1]=findMax(need[i-1],need[i]+1)
|
need[i-1] = findMax(need[i-1], need[i]+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//计算总共糖果
|
//计算总共糖果
|
||||||
for i:=0;i<len(ratings);i++{
|
for i := 0; i < len(ratings); i++ {
|
||||||
sum+=need[i]
|
sum += need[i]
|
||||||
}
|
}
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
func findMax(num1 int ,num2 int) int{
|
func findMax(num1 int, num2 int) int {
|
||||||
if num1>num2{
|
if num1 > num2 {
|
||||||
return num1
|
return num1
|
||||||
}
|
}
|
||||||
return num2
|
return num2
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 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的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
|
||||||
|
|
||||||
@ -222,48 +222,46 @@ class Solution:
|
|||||||
### Go
|
### Go
|
||||||
```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]//这个只是确保身高按照由大到小的顺序来排,并不确定K是按照从小到大排序的
|
return people[i][0] > people[j][0] // 身高按照由大到小的顺序来排
|
||||||
})
|
})
|
||||||
//再按照K进行插入排序,优先插入K小的
|
|
||||||
result := make([][]int, 0)
|
// 再按照K进行插入排序,优先插入K小的
|
||||||
for _, info := range people {
|
for i, p := range people {
|
||||||
result = append(result, info)
|
copy(people[p[1]+1 : i+1], people[p[1] : i+1]) // 空出一个位置
|
||||||
copy(result[info[1] +1:], result[info[1]:])//将插入位置之后的元素后移动一位(意思是腾出空间)
|
people[p[1]] = p
|
||||||
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() //创建链表
|
||||||
for i:=0;i<len(people);i++{
|
for i:=0; i < len(people); i++ {
|
||||||
position:=people[i][1]
|
position := people[i][1]
|
||||||
mark:=l.PushBack(people[i])//插入元素
|
mark := l.PushBack(people[i]) //插入元素
|
||||||
e:=l.Front()
|
e := l.Front()
|
||||||
for position!=0{//获取相对位置
|
for position != 0 { //获取相对位置
|
||||||
position--
|
position--
|
||||||
e=e.Next()
|
e = e.Next()
|
||||||
}
|
}
|
||||||
l.MoveBefore(mark,e)//移动位置
|
l.MoveBefore(mark, e) //移动位置
|
||||||
|
|
||||||
}
|
}
|
||||||
res:=[][]int{}
|
res := [][]int{}
|
||||||
for e:=l.Front();e!=nil;e=e.Next(){
|
for e := l.Front(); e != nil; e = e.Next() {
|
||||||
res=append(res,e.Value.([]int))
|
res = append(res, e.Value.([]int))
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
|
|
||||||
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。
|
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。
|
||||||
|
|
||||||
但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remote气球,只要记录一下箭的数量就可以了。
|
但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remove气球,只要记录一下箭的数量就可以了。
|
||||||
|
|
||||||
以上为思考过程,已经确定下来使用贪心了,那么开始解题。
|
以上为思考过程,已经确定下来使用贪心了,那么开始解题。
|
||||||
|
|
||||||
@ -175,25 +175,25 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
```golang
|
```go
|
||||||
func findMinArrowShots(points [][]int) int {
|
func findMinArrowShots(points [][]int) int {
|
||||||
var res int =1//弓箭数
|
var res int = 1 //弓箭数
|
||||||
//先按照第一位排序
|
//先按照第一位排序
|
||||||
sort.Slice(points,func (i,j int) bool{
|
sort.Slice(points, func (i,j int) bool {
|
||||||
return points[i][0]<points[j][0]
|
return points[i][0] < points[j][0]
|
||||||
})
|
})
|
||||||
|
|
||||||
for i:=1;i<len(points);i++{
|
for i := 1; i < len(points); i++ {
|
||||||
if points[i-1][1]<points[i][0]{//如果前一位的右边界小于后一位的左边界,则一定不重合
|
if points[i-1][1] < points[i][0] { //如果前一位的右边界小于后一位的左边界,则一定不重合
|
||||||
res++
|
res++
|
||||||
}else{
|
} else {
|
||||||
points[i][1] = min(points[i - 1][1], points[i][1]); // 更新重叠气球最小右边界,覆盖该位置的值,留到下一步使用
|
points[i][1] = min(points[i - 1][1], points[i][1]); // 更新重叠气球最小右边界,覆盖该位置的值,留到下一步使用
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
func min(a,b int) int{
|
func min(a, b int) int {
|
||||||
if a>b{
|
if a > b {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
这是前几天的leetcode每日一题,感觉不错,给大家讲一下。
|
这是前几天的leetcode每日一题,感觉不错,给大家讲一下。
|
||||||
|
|
||||||
这道题目刚一看,可能会有点懵,这要怎么找零才能保证完整全部账单的找零呢?
|
这道题目刚一看,可能会有点懵,这要怎么找零才能保证完成全部账单的找零呢?
|
||||||
|
|
||||||
**但仔细一琢磨就会发现,可供我们做判断的空间非常少!**
|
**但仔细一琢磨就会发现,可供我们做判断的空间非常少!**
|
||||||
|
|
||||||
@ -179,38 +179,23 @@ 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}
|
for i := 0; i < len(bills); i++ {
|
||||||
//第一个元素不为5,直接退出
|
if bills[i] == 5 {
|
||||||
if bills[0]!=5{
|
five++
|
||||||
return false
|
} else if bills[i] == 10 {
|
||||||
}
|
if five == 0 {
|
||||||
for i:=0;i<len(bills);i++{
|
|
||||||
//先统计5元和10元的个数
|
|
||||||
if bills[i]==5{
|
|
||||||
left[0]+=1
|
|
||||||
}
|
|
||||||
if bills[i]==10{
|
|
||||||
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