算法:贪心算法
本文主要介绍贪心算法及一些经典场景案例
算法核心:每次寻求最优解,直到满足最终需求。只看目前,不虑未来。又名:鼠目寸光
1. 分饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
示例 1:
输入: g = [1,2,3], s = [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
此题第一次做还想复杂了,每个孩子最多只能给一块饼干这句话没注意到…如果每个孩子顶多一块,那就很简单了。
思路:我们的目标是为了尽可能多的喂饱孩子,数量最大,那么就应该按照孩子们的胃口排个序,优先满足胃口小的,同时应该用最小的饼干。我们同时注意到每个孩子顶多一块饼干,所以就很简单了,直接排序+遍历,直到饼干用完。代码如下:
// 方案一: 暴力循环
const findContentChildren = () => {
// 1. 排序
const gSort = g.sort((a, b) => {
return a - b;
});
const sSort = s.sort((a, b) => {
return a - b;
});
// 2. 遍历
let count = 0;
for (let i = 0; i < gSort.length; i++) {
const resIndex = gSort.findIndex((item) => item >= gSort[i]);
if (resIndex) {
count++;
gSort.splice(resIndex, 1);
}
}
return count;
};
// 方案二:指针移动
/**
* @param {number[]} g
* @param {number[]} s
* @return {number}
*/
const findContentChildren = function(g, s) {
if(g.length === 0 || s.length === 0) return 0;
const g_sort = g.sort((a,b) => a - b);
const s_sort = s.sort((a,b) => a - b);
let gi = 0, si = 0;
while(gi < g_sort.length && si < s_sort.length){
if(g_sort[gi] <= s_sort[si]){
gi++
}
si++
}
return gi;
};
2. 凑钞票
一个土豪,身上带了足够的1、5、10、20、50、100元面值的钞票。现在您的目标是凑出某个金额w,需要用到尽量少的钞票。
思路: 为了输出最少的钞票,那我们每次取出的钞票,应该尽可能最大,以此达到数量的最小。先根据从大到小排序,每次及尽可能地用当前币值去消减总金额,直到达到最终的凑满目标金额。代码如下:
const f = (arr, target) => {
let res = []
arr.sort((a, b) => {
return b - a
})
console.log(arr)
while(target) {
const cur = arr.shift()
if (cur <= target) {
const num = Math.floor(target / cur)
target = target % cur
res.push({ key: cur, num: num})
}
}
return res
}
const arr = [1, 5, 10, 20, 50, 100]
let target = 666
console.log(f(arr, target))
输出:
[
{ key: 100, num: 6 },
{ key: 50, num: 1 },
{ key: 10, num: 1 },
{ key: 5, num: 1 },
{ key: 1, num: 1 }
]
但是吧,上面的场景,考虑另外一种情况:
const arr = [1, 5, 11]
let target = 15
贪心策略的输出:
[ { key: 11, num: 1 }, { key: 1, num: 4 } ]
用掉了五张钞票,但是很显然,为了凑满15, 三张五块即可实现。为什么?因为贪心算法的精髓: 鼠目寸光,只考虑眼下,无视未来。使用了一张11,其代价是要用四张一块去满足剩下的金额。
至于如何避免?详见动态规划篇
