贪心算法总结

优点:简单,高效,省去了为了找最优解可能需要穷举操作,通常作为其它算法的辅助算法来使用;

缺点:不从总体上考虑其它可能情况,每次选取局部最优解,不再进行回溯处理,所以很少情况下得到最优解。

每一步都选取当前状态下最好的选择(局部最优)。(整体不一定是最优解)
助记:贪心即比较贪婪只注重"眼前利益"不能长远考虑

正是因为原问题太复杂无法直接得到全局最优解,所以也无法判定贪心算法得到的结果是否逼近全局最优解,只要最终得到的结果在接受范围内即可

例题案例

注:以下两个案例均不能得到最优解,只能得到近似最优解,案例只是解释思想

1.找零钱问题

假设你开了间小店,不能电子支付,钱柜里的货币只有 25 分、10 分、5 分和 1 分四种硬币,如果你是售货员且要找给客户 41 分钱的硬币,如何安排才能找给客人的钱既正确且硬币的个数又最少?

思路:如果用贪心算法求解

要找给顾客41分且硬币数最少,那么大数值的硬币数越多越好。先用一个25分的,41-25=16。

然后根据局部最优当找零为16时从25,10,5,1中选一个,我们可以选10,16-10=6

找零数为6时从25,10,5,1中选一个,我们可以选5,6-5=1,以此类推

我们可以看到当做出一个选择后,然后相当于以现在的状态为起始状态,再次做出选择

*int* money=41;

int num_25=0,num_10=0,num_5=0,num_1=0;

//不断尝试每一种硬币
while(money>=25) { num_25++; money -=25; }
while(money>=10) { num_10++; money -=10; }
while(money>=5)  { num_5++;  money -=5; }
while(money>=1)  { num_1++;  money -=1; }

//输出结果
cout<< "25分硬币数:"<<num_25<<endl;
cout<< "10分硬币数:"<<num_10<<endl;
cout<< "5分硬币数:"<<num_5<<endl;
cout<< "1分硬币数:"<<num_1<<endl;

/*25分硬币数:1
10分硬币数:1
5分硬币数:1
1分硬币数:1*/

2.01背包问题

有一个背包,最多能承载重量为 C=150的物品,现在有7个物品(物品不能分割成任意大小),编号为 1~7。

重量分别是 wi=[35,30,60,50,40,10,25],价值分别是 pi=[10,40,30,50,35,40,30]。

现在从这 7 个物品中选择一个或多个装入背包,要求在物品总重量不超过 C 的前提下,所装入的物品总价值最高。

思路:若用贪心算法,有3种策略

  1. 价值主导选择,每次都选价值最高的物品放进背包;
  2. 重量主导选择,每次都选择重量最轻的物品放进背包;
  3. 价值密度主导选择,每次选择都选价值/重量最高的(性价比最高的)物品放进背包。

策略1:每次优先选价值最高的

解:按照价值排序则放入背包的编号依次为4、2、6、5。

其价值为50+40+40+35=165,其重量为50+30+10+40=130

策略2:每次优先选重量最轻的

解:按照重量最轻则放入的编号依次为6、7、2、1、5

其价值为40+30+40+10+35=155,其重量为10+25+30+35+40=140

策略3:每次优先选价值/重量最大的

解:这7件物品的价值密度分别为0.286、1.333、0.5、1.0、0.875、4.0、1.2

所以放入的编号依次为6、2、7、4、1

其价值为40+40+30+50+10=170,其重量为10+30+25+50+35=150

LeetCode习题

🚩1.题目1221分割平衡字符串问题

在一个 平衡字符串 中,‘L’ 和 ‘R’ 字符的数量是相同的。给你一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。

注意:分割得到的每个字符串都必须是平衡字符串。返回可以通过分割得到的平衡字符串的最大数量 。

输入:s = “RLRRLLRLRL”
输出:4
解释:s 可以分割为 “RL”、“RRLL”、“RL”、“RL” ,每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’ 。

解:用变量balance(初始为0)记录扫描到的L和R的数目,遇到L则balance+1否则减1当其为0的时候说明当前找到了平衡子串

上一次划分后balance=0,剩下的平衡子串接着用上述思想(贪心思想)

int balancedStringSplit(string s) {
      int len=s.length();
	    int balance=0,result=0;
	    for (int i = 0; i < len; i++)
	    {
		    if(s[i]=='L')	balance++;
		    if(s[i]=='R')	balance--;
		    if(balance==0)	result++;
	    }
	    return result;
    }
### 贪心算法的核心思想 贪心算法是一种通过逐步做出局部最优的选择来解决问题的方法,其目标是在每一步都选择当前情况下最好的选项,从而期望最终得到全局最优解[^2]。然而需要注意的是,这种策略并不总是能够保证获得真正的全局最优解,因此在应用时需谨慎验证。 #### 局部最优与整体最优的关系 贪心算法的关键在于如何定义“局部最优”。例如,在找零钱问题中,优先使用面额较大的钞票可以减少所需钞票的数量,这是一种直观的局部最优策略[^2]。但是并非所有问题都能如此简单地解决;某些复杂场景下可能需要更深入的理解才能正确设计出有效的贪心规则。 #### 学习过程中的挑战与成长 对于初学者而言,掌握贪心算法可能会遇到一定困难。正如一位学习者所描述,“刚开始都不怎么会做”,这表明初次接触此类方法时常感到困惑甚至无从下手[^1]。面对这些问题,可以通过观看在线教程、查阅参考资料以及与其他同学交流等方式逐渐积累经验并形成自己的思考模式。“慢慢地才对贪心算法有了一些规律上的总结”,说明持续的努力加上实践是非常重要的环节之一[^1]。 以下是基于C++实现的一个典型例子——跳跃游戏(Jump Game),它展示了如何利用贪心思路高效求解特定类型的问题: ```cpp #include <iostream> using namespace std; int canJump(int* nums, int size){ int lastPos = size - 1; for (int i = size - 1; i >= 0; --i){ if (i + nums[i] >= lastPos){ lastPos = i; } } return lastPos == 0 ? 1 : 0; } int main(){ int a[] = {2,3,1,1,4}; cout << canJump(a,sizeof(a)/sizeof(*a))<< endl; } ``` 此程序片段实现了这样一个功能:给定一系列非负整数表示每个位置的最大跳远距离,请判断是否可以从第一个位置出发到达最后一个位置。这里采用逆向思维的方式,不断更新最远可达到的位置直到起点为止[^3]。 ### 结论 综上所述,虽然贪心算法看似简单易懂,但在实际运用过程中仍需仔细考量各种因素以确保解决方案的有效性和准确性。随着不断的练习和探索,人们不仅可以提升对该技术的认识水平,而且还能培养良好的编程习惯和技术素养。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值