贪心算法(又称贪婪算法)是指,在对问题求解)时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
一、 柠檬水找零
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
注意:
你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。
示例 1:
输入: [1,2,3], [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
示例 2:
输入: [1,2], [1,2,3]
输出: 2
解释:
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.
这是一道典型的动态规划题目:找零。
- 如果收到5块的,就保存起来
- 如果收到10块的,就检查是否有五块的去找零,然后把十块的保存起来
- 关键是收到20的,这里就用到贪心算法。因为10是5的倍数,一张10块的能做的两张5块的也能做,反过来则不行,所以10的优先级要低于5块的。换句话说就是:两张5块的要优于一张10块的。所以我们就要先去检查是否有10块的,然后再去检查5块的
var lemonadeChange = function(bills) {
let five = ten = 0
for (const b of bills) {
if(b == 5) five++
else if(b == 10){
if(five-- > 0) ten++
else return false
}else{
if(ten > 0){
ten--
if(five-- <= 0) return false
}else{
if(five >= 3) five -= 3
else return false
}
}
}
return true
};
如果是这里的钱数不是5,10,20这种有倍数关系的,而是2,5,9等等这种没什么联系的钱币,就不能用到贪心算法了。
二、 分发糖果
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻的孩子中,评分高的孩子必须获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入: [1,0,2]
输出: 5
解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入: [1,2,2]
输出: 4
解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
这道题目关键是在于需要同时判断当前值和两侧的关系,我们可以利用贪心算法:分别从两边遍历,根据和两侧的关系来配置,然后取两边遍历结果的最大值即可
var candy = function(ratings) {
let left = Array(ratings.length).fill(1),right = Array(ratings.length).fill(1)
let sum = 0
for(let i = 1; i < ratings.length; i++){
if(ratings[i] > ratings[i - 1]) left[i] = left[i - 1] + 1
}
for(let i = ratings.length - 1; i >= 0; i--){
if(i < ratings.length - 1 && ratings[i] > ratings[i + 1]) right[i] = right[i + 1] + 1
sum += Math.max(left[i],right[i])
}
return sum
};
三、 按要求补齐数组
给定一个已排序的正整数数组 nums,和一个正整数 n 。从 [1, n] 区间内选取任意个数字补充到 nums 中,使得 [1, n] 区间内的任何数字都可以用 nums 中某几个数字的和来表示。请输出满足上述要求的最少需要补充的数字个数。
示例 1:
输入: nums = [1,3], n = 6
输出: 1
解释:
根据 nums 里现有的组合 [1], [3], [1,3],可以得出 1, 3, 4。
现在如果我们将 2 添加到 nums 中, 组合变为: [1], [2], [3], [1,3], [2,3], [1,2,3]。
其和可以表示数字 1, 2, 3, 4, 5, 6,能够覆盖 [1, 6] 区间里所有的数。
所以我们最少需要添加一个数字。
示例 2:
输入: nums = [1,5,10], n = 20
输出: 2
解释: 我们需要添加 [2, 4]。
示例 3:
输入: nums = [1,2,2], n = 5
输出: 0
根据贪心算法,如果 [1, n] 区间内的任何数字都可以用 nums 中某几个数字的和来表示,那么只需要有n/2以及 [1, n/2] 区间内任何数字都可以用 nums 中某几个数字的和来表示即可
var minPatches = function(nums, n) {
let head = 1
let i = res = 0
while(head <= n){
if(i < nums.length && nums[i] <= head) head += nums[i++]
else{
head *= 2
res++
}
}
return res
};
网友评论