目录
贪心算法思想
贪心算法是指求解问题时,会做出在当前看来最优的选择。也即是不考虑整体的最优解,仅考虑局部最优解。
贪心算法关键在于贪心策略的选择。贪心选择的意思是对于所求问题的整体最优解,可以通过一系列的局部最优选择求得。需要注意的是,贪心选择须具备无后效性,也即是某个状态不会影响之前求得的局部最优解。
求解步骤
1.将问题分解为若干个子问题
2.找出合适的贪心策略
3.求解每一个子问题的最优解
4.将局部最优解堆叠成全局最优解
贪心算法案例
分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
来源:力扣(LeetCode)
链接:力扣
分析:利用贪心思想来看待这道题,就是要尽可能满足更多的孩子。 那么在饼干数量有限的情况下,我们就得先满足胃口小的孩子,再去满足胃口大的孩子,这样才能保证能够满足更多的孩子。
/**
* @param {number[]} g
* @param {number[]} s
* @return {number}
*/
var findContentChildren = function(g, s) {
g.sort((a,b) => (a-b)); //从小到大排序
s.sort((a,b) => (a-b));
let children = 0; //孩子指针
let yummy = 0; //饼干指针
while(children < g.length && yummy < s.length){
if(g[children] <= s[yummy]){
children++;
}
yummy++;
}
return children;
};
跳跃游戏
给定一个非负整数数组 nums ,你最初位于数组的第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
来源:力扣(LeetCode)
链接:力扣
分析:首先我们分析题目,要到达最后一个位置, 就需要最后一跳的距离加上该位置下标能够大于等于数组长度,然后依次往前推,当前元素也处于前一个元素最远可以到达的范围之内,这也即是贪心算法的思想。
/**
* @param {number[]} nums
* @return {boolean}
*/
var canJump = function(nums) {
let max = 0;
for(let i=0;i<nums.length;i++){
if(i > max){
return false;
}
max = Math.max(max, i + nums[i]); //取较大值
if(max >= nums.length - 1){
return true;
}
}
return false;
};
背包问题
有一个背包,背包容量是M=200。有8个物品,物品可以分割成任意大小。
要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
物品 A B C D E F G H 重量 10 25 60 50 35 15 30 55 价值 5 10 20 15 30 20 30 10
分析:首先我们要先获得每一种物品单位重量的价值,依据贪心选择策略,在不超过背包容量的情况下,将尽可能多的单位重量价值最高的物品装入背包,直至背包装满。
function backpage(All,weight,value){
let arr = [];
for(let i=0;i<weight.length;i++){
let obj = {
name:String.fromCharCode(65+i), //物品名称
wei:weight[i], //物品重量
val:value[i], //物品价值
val_wei:(value[i]/weight[i]).toFixed(2), //获取价值比
get:false //标记物品是否存入背包
}
arr.push(obj);
}
let weightAll = 0; //总重量
let valueAll = 0; //总价值
let max = 0; //当前最高价值
let array = []; //放入背包物品顺序表
let flag = 0; //获取价值比最高物品索引
let n = 0; //最终放入背包物品索引
//将arr数组按照价值比进行从大到小排序
for(let m=0;m<weight.length;m++){
for(let n=m+1;n<weight.length;n++){
if(arr[m].val_wei < arr[n].val_wei){
let temp = arr[m];
arr[m] = arr[n];
arr[n] = temp;
}
}
}
while(weightAll <= All){
max = arr[weight.length-1].val_wei; //获取最小价值比作为初始max
for(let j=0;j<weight.length;j++){
if(arr[j].val_wei > max && arr[j].get === false){
max = arr[j].val_wei;
flag = j;
}
}
array[n++] = arr[flag].name;
arr[flag].get = true; //标记物品已放入背包
weightAll += arr[flag].wei; //计算总容量
valueAll += arr[flag].val; //计算总价值
}
let str = "";
for(let k=0;k<n-1;k++){
str += array[k] + '\t';
}
console.log("最终放入背包中的物品有",str);
console.log("物品总重量为",weightAll-arr[flag].wei);
console.log("物品总价值为",valueAll-arr[flag].val);
}
backpage(200,[10,25,60,50,35,15,30,55],[5,10,20,15,30,20,30,10]);
所得结果:
最大整数
设有n个正整数,将它们连接成一排,组成一个最大的多位整数。
例如:n=3时,3个整数13,312,343,连成的最大整数为34331213。
又如:n=4时,4个整数4,7,13,246,连成的最大整数为7424613。
分析: 首先先将整数转换为字符串,然后比较a+b和b+a,将大的放在前面,小的放在后面,如此反复便可得出最大整数
function maxNum(nums){
let last = "";
for(let i=0;i<nums.length;i++){
for(let j=i+1;j<nums.length;j++){
let num1 = nums[i] + ""; //数字转字符串
let num2 = nums[j] + "";
if((num1+num2) < (num2+num1)){
let temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
}
}
for(let i=0;i<nums.length;i++){
last += nums[i];
}
return last;
}
let max = maxNum([12,121,23,42,1,6,71,21]);
console.log("组成最大整数:"+max); //组成最大整数:716422321121211
性能分析
优越性
1.适合用于组合优化问题
2.能做出在当前来看最好的选择
局限性
1.不能保证求得的解整体来看是最优解,并非所有问题都可以通过局部最优解得到整体最优解
2.无法用来求解最大或者最小问题
3.只能用来求解满足某些约束条件的可行解的范围
4.贪心的选择需要具备无后效性条件