参考代码可见:https://github.com/dashnowords/blogs/tree/master/Structure/GreedyAlogrithm前端
贪心算法
属于比较简单的算法,它老是会选择当下最优解,而不去考虑单次递归时是否会对将来形成影响,也就是说不考虑获得的解是不是全局最优。在不少实际问题中,寻找全局最优解的代价是很是大的,这时候就能够经过求次优解来解决问题,这种思想其实在软件工程中很常见,例如React
中著名的DOM Diff
算法中须要对比两棵DOM树,树的彻底对比时间复杂度为O(n^3),而React团队经过只比较同层节点的策略将问题简化为O(n),也就是说获得的结果从全局角度来讲并不必定是绝对最优的,可是它能够在大多数状况下表现并不差。git
下面经过几个简单例子来理解贪心算法
(题目来自《数据结构与算法Javascript描述》一书)。github
贪心算法求解背包问题实际上很像人工求解,若是你是一个大盗,本身带着背包在宝库挑东西,总不能拿一张草稿纸出来开始动态规划或手动递归吧,那等你求出结果来估计警察也来了,可能的作法例如:算法
这几种方式均可以做为贪心算法的一部分参与计算,获得的结果也不必定是同样的,但均可以认为是一种局部最优解,同时也多是全局最优解。数据结构
示例算法实现:ide
/** * 贪心算法求解背包问题局部最优解 */ function ksack(values, weights, capacity, n) { var load = 0; var i =0; var w = 0; while (load < capacity && i < n){ if(weights[i] <= (capacity-load)){ w += values[i]; load += weights[i]; }else{ var r = (capacity - load) / weights[i]; w += r * values[i]; load += weights[i]; } i++; } return w; } var items = ["A","B","C","D"]; var values = [50, 140, 60 ,60]; var weights = [5, 20, 10, 12]; var n = 4; var capacity = 30; console.log(ksack(values,weights, capacity, n))
书中第14章练习题1:使用暴力技巧求解最长公共子串测试
3.1 题解:code
暴力求解公共字符串的方法,从较短的字符串总体开始找起,逐步缩小步长,例如长字符串为long_str
,较短的字符串称为short_str
,假设short_str
的长度为6,先查看short_str
是否整个包含在long_str
中,若是是则返回,若是不是,再将步长设置为5,而后查看short_str[0,5)
, short_str[1,6)
这两个字符串是否在long_str
中,以此类推,过程和找零问题很类似。blog
3.2 参考代码:递归
/** * 贪心算法寻找公共子串 */ function greedy_lsc(str1, str2) { //保证str2是长度较短的序列 if (str1.length < str2.length) { let temp = str1; str1 = str2; str2 = temp; } let stepLength = str2.length; //从长到短枚举 while(stepLength >= 0){ for(let i = 0; i < str2.length - stepLength; i++){ //至关于拿一个不断缩短的尺子逐段截取来查看截取的片断是否被长字符串包含, //一旦找到则就是最长公共子串 let checking = str2.slice(i, i+stepLength); if (contains(str1,checking)) { return checking; } } stepLength--; } } //str2是不是str1的子串 function contains(str1, str2) { return str1.indexOf(str2) !== -1; } //测试 let str1 = 'aabcdefsssefce'; let str2 = 'abssefsssse'; console.log(greedy_lsc(str1,str2));
书中第14章练习题3:使用贪心算法求解找零问题,要求不能用10美分,须要找零30美分。
4.1 题解:
书中有例题,没什么难度,就不展开讲了,仅提供参考代码。
4.2 参考代码:
/** * 贪心算法求解零钱问题 * 要求:不能使用10美分 */ function makeChange(money, coins) { let remain = money; if (remain / 25 > 0) { coins[2] = parseInt(remain / 25, 10); remain = remain - coins[2]*25; } if (remain / 5 > 0) { coins[1] = parseInt(remain / 5 , 10); remain = remain - coins[1]*5; } coins[0] = remain; } /** * 显示结果 */ function showChange(coins) { if (coins[2] > 0) { console.log('25美分-' + coins[2]); } if (coins[1] > 0) { console.log('5美分-' + coins[1]); } if (coins[0] > 0) { console.log('1美分-' + coins[0]); } } var origAmt = 30; var coins = []; makeChange(origAmt, coins); showChange(coins);