mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-07 07:35:35 +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
|
||||
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
|
||||
// 贪心版本一
|
||||
func jump(nums []int) int {
|
||||
@ -320,8 +295,6 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Javascript
|
||||
|
||||
```Javascript
|
||||
|
@ -176,13 +176,13 @@ public:
|
||||
* 时间复杂度:$O(n)$
|
||||
* 空间复杂度:$O(1)$
|
||||
|
||||
**说这种解法为贪心算法,才是是有理有据的,因为全局最优解是根据局部最优推导出来的**。
|
||||
**说这种解法为贪心算法,才是有理有据的,因为全局最优解是根据局部最优推导出来的**。
|
||||
|
||||
## 总结
|
||||
|
||||
对于本题首先给出了暴力解法,暴力解法模拟跑一圈的过程其实比较考验代码技巧的,要对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](之前比较右孩子大于左孩子得到的糖果数量)。
|
||||
|
||||
那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量即大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
|
||||
那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
|
||||
|
||||
局部最优可以推出全局最优。
|
||||
|
||||
@ -172,63 +172,44 @@ class Solution:
|
||||
```
|
||||
|
||||
### Go
|
||||
```golang
|
||||
```go
|
||||
func candy(ratings []int) int {
|
||||
/**先确定一边,再确定另外一边
|
||||
1.先从左到右,当右边的大于左边的就加1
|
||||
2.再从右到左,当左边的大于右边的就再加1
|
||||
**/
|
||||
need:=make([]int,len(ratings))
|
||||
sum:=0
|
||||
//初始化(每个人至少一个糖果)
|
||||
for i:=0;i<len(ratings);i++{
|
||||
need[i]=1
|
||||
need := make([]int, len(ratings))
|
||||
sum := 0
|
||||
// 初始化(每个人至少一个糖果)
|
||||
for i := 0; i < len(ratings); i++ {
|
||||
need[i] = 1
|
||||
}
|
||||
//1.先从左到右,当右边的大于左边的就加1
|
||||
for i:=0;i<len(ratings)-1;i++{
|
||||
if ratings[i]<ratings[i+1]{
|
||||
need[i+1]=need[i]+1
|
||||
// 1.先从左到右,当右边的大于左边的就加1
|
||||
for i := 0; i < len(ratings) - 1; i++ {
|
||||
if ratings[i] < ratings[i+1] {
|
||||
need[i+1] = need[i] + 1
|
||||
}
|
||||
}
|
||||
//2.再从右到左,当左边的大于右边的就右边加1,但要花费糖果最少,所以需要做下判断
|
||||
for i:=len(ratings)-1;i>0;i--{
|
||||
if ratings[i-1]>ratings[i]{
|
||||
need[i-1]=findMax(need[i-1],need[i]+1)
|
||||
// 2.再从右到左,当左边的大于右边的就右边加1,但要花费糖果最少,所以需要做下判断
|
||||
for i := len(ratings)-1; i > 0; i-- {
|
||||
if ratings[i-1] > ratings[i] {
|
||||
need[i-1] = findMax(need[i-1], need[i]+1)
|
||||
}
|
||||
}
|
||||
//计算总共糖果
|
||||
for i:=0;i<len(ratings);i++{
|
||||
sum+=need[i]
|
||||
for i := 0; i < len(ratings); i++ {
|
||||
sum += need[i]
|
||||
}
|
||||
return sum
|
||||
}
|
||||
func findMax(num1 int ,num2 int) int{
|
||||
if num1>num2{
|
||||
func findMax(num1 int, num2 int) int {
|
||||
if num1 > num2 {
|
||||
return num1
|
||||
}
|
||||
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
|
||||
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
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后在按照另一个维度重新排列。
|
||||
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后再按照另一个维度重新排列。
|
||||
|
||||
其实如果大家认真做了[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html),就会发现和此题有点点的像。
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
|
||||
**如果两个维度一起考虑一定会顾此失彼**。
|
||||
|
||||
对于本题相信大家困惑的点是先确定k还是先确定h呢,也就是究竟先按h排序呢,还先按照k排序呢?
|
||||
对于本题相信大家困惑的点是先确定k还是先确定h呢,也就是究竟先按h排序呢,还是先按照k排序呢?
|
||||
|
||||
如果按照k来从小到大排序,排完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
|
||||
|
||||
@ -222,48 +222,46 @@ class Solution:
|
||||
### Go
|
||||
```go
|
||||
func reconstructQueue(people [][]int) [][]int {
|
||||
//先将身高从大到小排序,确定最大个子的相对位置
|
||||
sort.Slice(people,func(i,j int)bool{
|
||||
if people[i][0]==people[j][0]{
|
||||
return people[i][1]<people[j][1]//这个才是当身高相同时,将K按照从小到大排序
|
||||
// 先将身高从大到小排序,确定最大个子的相对位置
|
||||
sort.Slice(people, func(i, j int) bool {
|
||||
if people[i][0] == people[j][0] {
|
||||
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)
|
||||
for _, info := range people {
|
||||
result = append(result, info)
|
||||
copy(result[info[1] +1:], result[info[1]:])//将插入位置之后的元素后移动一位(意思是腾出空间)
|
||||
result[info[1]] = info//将插入元素位置插入元素
|
||||
|
||||
// 再按照K进行插入排序,优先插入K小的
|
||||
for i, p := range people {
|
||||
copy(people[p[1]+1 : i+1], people[p[1] : i+1]) // 空出一个位置
|
||||
people[p[1]] = p
|
||||
}
|
||||
return result
|
||||
return people
|
||||
}
|
||||
```
|
||||
```go
|
||||
//链表法
|
||||
// 链表实现
|
||||
func reconstructQueue(people [][]int) [][]int {
|
||||
sort.Slice(people,func (i,j int) bool {
|
||||
if people[i][0]==people[j][0]{
|
||||
return people[i][1]<people[j][1]//当身高相同时,将K按照从小到大排序
|
||||
if people[i][0] == people[j][0] {
|
||||
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()//创建链表
|
||||
for i:=0;i<len(people);i++{
|
||||
position:=people[i][1]
|
||||
mark:=l.PushBack(people[i])//插入元素
|
||||
e:=l.Front()
|
||||
for position!=0{//获取相对位置
|
||||
l := list.New() //创建链表
|
||||
for i:=0; i < len(people); i++ {
|
||||
position := people[i][1]
|
||||
mark := l.PushBack(people[i]) //插入元素
|
||||
e := l.Front()
|
||||
for position != 0 { //获取相对位置
|
||||
position--
|
||||
e=e.Next()
|
||||
e = e.Next()
|
||||
}
|
||||
l.MoveBefore(mark,e)//移动位置
|
||||
l.MoveBefore(mark, e) //移动位置
|
||||
|
||||
}
|
||||
res:=[][]int{}
|
||||
for e:=l.Front();e!=nil;e=e.Next(){
|
||||
res=append(res,e.Value.([]int))
|
||||
res := [][]int{}
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
res = append(res, e.Value.([]int))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -56,7 +56,7 @@
|
||||
|
||||
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。
|
||||
|
||||
但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remote气球,只要记录一下箭的数量就可以了。
|
||||
但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remove气球,只要记录一下箭的数量就可以了。
|
||||
|
||||
以上为思考过程,已经确定下来使用贪心了,那么开始解题。
|
||||
|
||||
@ -175,25 +175,25 @@ class Solution:
|
||||
```
|
||||
|
||||
### Go
|
||||
```golang
|
||||
```go
|
||||
func findMinArrowShots(points [][]int) int {
|
||||
var res int =1//弓箭数
|
||||
var res int = 1 //弓箭数
|
||||
//先按照第一位排序
|
||||
sort.Slice(points,func (i,j int) bool{
|
||||
return points[i][0]<points[j][0]
|
||||
sort.Slice(points, func (i,j int) bool {
|
||||
return points[i][0] < points[j][0]
|
||||
})
|
||||
|
||||
for i:=1;i<len(points);i++{
|
||||
if points[i-1][1]<points[i][0]{//如果前一位的右边界小于后一位的左边界,则一定不重合
|
||||
for i := 1; i < len(points); i++ {
|
||||
if points[i-1][1] < points[i][0] { //如果前一位的右边界小于后一位的左边界,则一定不重合
|
||||
res++
|
||||
}else{
|
||||
} else {
|
||||
points[i][1] = min(points[i - 1][1], points[i][1]); // 更新重叠气球最小右边界,覆盖该位置的值,留到下一步使用
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
func min(a,b int) int{
|
||||
if a>b{
|
||||
func min(a, b int) int {
|
||||
if a > b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
|
@ -54,7 +54,7 @@
|
||||
|
||||
这是前几天的leetcode每日一题,感觉不错,给大家讲一下。
|
||||
|
||||
这道题目刚一看,可能会有点懵,这要怎么找零才能保证完整全部账单的找零呢?
|
||||
这道题目刚一看,可能会有点懵,这要怎么找零才能保证完成全部账单的找零呢?
|
||||
|
||||
**但仔细一琢磨就会发现,可供我们做判断的空间非常少!**
|
||||
|
||||
@ -179,38 +179,23 @@ class Solution:
|
||||
|
||||
### Go
|
||||
|
||||
```golang
|
||||
```go
|
||||
func lemonadeChange(bills []int) bool {
|
||||
//left表示还剩多少 下标0位5元的个数 ,下标1为10元的个数
|
||||
left:=[2]int{0,0}
|
||||
//第一个元素不为5,直接退出
|
||||
if bills[0]!=5{
|
||||
return false
|
||||
}
|
||||
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 {
|
||||
ten, five := 0, 0
|
||||
for i := 0; i < len(bills); i++ {
|
||||
if bills[i] == 5 {
|
||||
five++
|
||||
} else if bills[i] == 10 {
|
||||
if five == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if tmp==15{
|
||||
if left[1]>0&&left[0]>0{
|
||||
left[0]-=1
|
||||
left[1]-=1
|
||||
}else if left[1]==0&&left[0]>2{
|
||||
left[0]-=3
|
||||
}else{
|
||||
ten++; five--
|
||||
} else {
|
||||
if ten >= 1 && five >= 1 {
|
||||
ten--; five--
|
||||
} else if five >= 3 {
|
||||
five -= 3
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user