贪心算法总结

JavaScript013

贪心算法总结,第1张

做了这10道题,其实发现贪心算法没有什么规律,要说有什么共同特点就是都是由局部最优从而推出全局最优,每个题基本上都要考虑其局部最优是什么,其全局最优是什么,所以虽然都用到了贪心算法的思想,但是题与题之间又没有什么规律可言。

现在把这10道题的思路总结一下(总结主要以我的主观看法在写,可能别人看会不知道我在说什么)

1.分发饼干:

https://programmercarl.com/0455.%E5%88%86%E5%8F%91%E9%A5%BC%E5%B9%B2.html

思路:想要完成最多的小孩满足,那么就得最小的饼干给胃口最小的小孩

这里的贪心思想,

局部最优就是尽可能让一个饼干喂饱一个

全局最优就是最多的小孩满足

2.摆动序列:

https://programmercarl.com/0376.%E6%91%86%E5%8A%A8%E5%BA%8F%E5%88%97.html

思路:这里要找到最长的摆动序列,那么其实就是找那些波峰波谷,如图所示

可以看出来,在到达波峰波谷的路上有几个数字不会影响什么,可以直接去掉。

那么这里的局部最优就是把单调坡上的点删掉,保留最多的波峰波谷

全局最优就是得到对多的波峰波谷,即最长的摆动序列

3.最大子序和

https://programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C.html

这道题显然可以暴力解出来,即列出所有子序和,找出最大的,不过计算量会比贪心大很多。

这里主要介绍贪心解的思想:

想要得到最大子序和,就得保证每次相加时,相加后不能为负数,因为负数继续往下加一定是拉低总和的,那么我们当加成到负数时就重新从下个数开始加,并实时记录最大的子序和,这样一遍循环就能得出最大子序和。

局部最优:加成负数就立刻停止,并从下个元素重新开始

全局最优:得到最大子序和

4.买卖股票的最佳时机II

https://programmercarl.com/0122.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAII.html

思路:想要得到最大利润,那就要低价买入高价卖出,那么怎样的买卖才能得到最大利润呢。

这里就体现出贪心算法的“贪”字(我猜的),这道题贪在哪呢,贪在只要有利可图就去做,即只要今天买入的价钱比明天卖出的价钱底,即有利可图,那么我就去做,做就是在今天买入,在明天卖出。

局部最优:得到每天的最大正利润

全局最优:得到最大利润

5.跳跃游戏

https://programmercarl.com/0055.%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F.html

思路:每个数组的元素代表的是可以跳的最远下标,那么我们只要使那个最远下标包含最后一个下标就是可以跳到,那么我们每跳到一个位置就要更新那个可以跳的范围,即可以跳到的最远下标。

局部最优:每次跳跃都得出最远的跳跃范围

全局最优:最后能跳到的最大范围

6.跳跃游戏II

https://programmercarl.com/0045.%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8FII.html

思路:这道题要得到最小的跳跃数,其实只要保证跳的是位置是可以跳范围内更新最远范围的位置就可以了。

为什么这么说呢?以题例来说:

我们刚开始在‘0’的位置,我们能跳到‘1’和‘2’的位置,那么我们怎么跳呢?可以看到跳到‘1’之后更新的最大范围是‘4’,跳到‘2’之后更新的最大范围是‘3’,所以我们就跳‘2’了,因为跳‘1’之后更新的最大可跳范围更大包含了跳‘2’的最大可跳范围,那么肯定是跳‘3’最优呀,这里就体现了局部最优的思想。

局部最优:每次跳后,更新的最大可调范围最大

全局最优:跳跃次数最少

7.K次取反后最大化的数组和

https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.html

思路:想要得到最大数组和,我们就可以想到怎样做呢?

一,尽可能保证负数最少

二,负数绝对值大的优先变正

三,正数绝对值小的优先变负,有零变零

本着这三条原则做,就能做出来。

那么这道题体现了什么贪心思想呢?

我感觉,前面那三条都是贪心中‘贪’的体现

在负数中,局部最优就是:绝对值大的负数优先变正

在正数中,局部最优就是:绝对值小的正数变负,有零变零

得到的全局最优:数组和最大

8.加油站

https://programmercarl.com/0134.%E5%8A%A0%E6%B2%B9%E7%AB%99.html

思路:首先可以想到这道题是可以暴力解出来了,即分别以每个加油站为起点,得出可以跑一圈的加油站

那么贪心思想做,该怎么做呢,首先可以想到,如果以一个1点为起点当跑着跑着跑到3,油变为负数时,那么说明以这个起点是不行的,但是以2或3为起点行不行呢?答案肯定是不行的,因为1跑到3,油变为负,说明1~3的gas=0的,所以可以得出,如果1~3油数变为负数,那么由2~3油数肯定也为负数。

所以这里就可以得出,如果经过几个加油站油数变为负了,那么起点就更新为这一段路的下个加油站跑

局部最优:油量一旦为负,就从下个加油站重新跑

全局最优:得出可以跑一圈的加油站起点

9.分发糖果

https://programmercarl.com/0135.%E5%88%86%E5%8F%91%E7%B3%96%E6%9E%9C.html

思路:每个孩子至少一个,如果一个孩子比他旁边的孩子优秀,就要比他旁边的糖果多,这道题一旦两边都考虑很容易顾此失彼,所以我们就定义两个循环,分别从左到右,从右到左去考虑,只要更优秀则比他旁边的多1,如果已经多了就不用变了。

局部最优:保证优秀的孩子比他旁边的孩子糖果多

全局最优:满足题中条件,至少要发的糖果

10.柠檬水找零

https://programmercarl.com/0860.%E6%9F%A0%E6%AA%AC%E6%B0%B4%E6%89%BE%E9%9B%B6.html

思路:我们在找零时要遵守的规则一定是:

5 得5

10 得10减5

15 得15,优先减一个10减一个5  如果10块没有则减三个5

局部最优:以最少用的5块的方式找零

全局最优:得到找零能否进行下去

贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择

举个简单的贪心算法: 柠檬水找零

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。每位顾客只买一杯柠檬水,然后向你付

5 美元或10 美元或 20 美元。

你必须给每个顾客正确找零,注意,一开始你手头没有任何零钱。如果你能给每位顾客正确找零,返回 true ,否则返回 false

#include <stdio.h>

#define N 1000

int greedy(int d[],int n,int k)

{

int num = 0

int i=0

int s=0

for( i = 0i <ki++)

{

if(d[i] >n)

{

printf("no solution\n")

return 0

}

}

for( i = 0,s = 0i <ki++)

{

s += d[i]

if(s >n)

{

num++

s = d[i]

}

}

printf("%d\n",num)

return 1

}

void main()

{

int i,n,k

int d[N]

printf("请输入汽车可行驶: \n")

scanf("%d",&n)

printf("加油站的个数: \n")

scanf("%d",&k)

for(i=0i<k+1i++)

{

printf("请输入第%d段路的长度: ",i+1)

scanf("%d",&d[i])

fflush(stdin)

}

greedy(d,n,k+1)

}