点击上方蓝字关注我们吧
大家好!上周的公众号《办公自动化常见问题与套路——查找连续范围》发布后,很多初学编程的朋友反映“套路很实用,但理解有难度”。所以今天杨老师选了一个更基础也更常见的问题 —— 查找最大值或最小值,专供初学者理解编程之用。
本次在课堂上讲到“查找最大值”问题,我总会想起老家的一句歇后语 —— “熊瞎子掰苞米,掰一穗丢一穗”。大意就是:狗熊在偷盗农田的玉米时,掰下一穗就夹在腋下;但是当它抬起胳膊把第二穗掰下来夹在腋下时,前面那一穗自然先掉到落到地上。如此反复,忙到最终也只带走一穗玉米。
没办法,估计可怜的狗熊家里连个购物袋都没有,所以想让它带走两穗以上玉米确实有些“强熊所难”。不过即使只有一个腋窝可用,它的工作效率也有明显的提升空间,那就是 —— 虽然只能带走一穗玉米,但可以保证它是“最大的玉米”。
这就是一个非常典型的“查找最大值”问题。老规矩,还是首先启动杨老师的灵魂画笔,图解这个思维过程:
这个思维过程确实非常简单,只要狗熊能够记住“当前夹在腋下的玉米”的尺寸,然后每次掰苞米之前能够做一个判断,就可以循环反复,最终留下最大玉米。
再换一个更通用的说法:这个“当前腋下玉米”,其实就是狗熊眼中截至目前的玉米“世界纪录”;而每次发现更大的玉米,就是“打破世界纪录”;相应地,就要“更新世界纪录”,也就是把更大的玉米换到腋下。而在刚刚进入玉米田、还没有开始采玉米时,狗熊眼中的世界纪录是“0”,也就是理论上“最小的玉米”。
想到这一层,套路代码呼之即出 :
现在我们就看一下,怎样把上面的套路应用到开头那个案例中,找出“获胜次数/单挑总数”最高的梁山将领,并将其所在单元格高亮显示:
与前面的套路对照,本案例的关键字如下:
“世界纪录” —— “最大胜率”
“比理论最差值更差的值” —— -1 。因为理论上最低的胜率是0,所以我们选择比0还小的-1(当然也可以是-0.5、-2等等);
“第i条数据” —— 第i行E列单元格 ÷ 第i行D列单元格
“打破记录” —— 第i行数据大于世界记录
将它们代入套路代码,得到如下程序(仍以VBA为例,Python代码雷同):
除了查找“最大值”,查找“最小值”的情况也完全符合本套路。比如把刚才的需求改成“找到胜率最低的将领并高亮”,那么对应的“套路关键字”就变成:
“世界纪录” —— “最小胜率”
“比理论最差值更差的值” —— 2 ,因为这一次的选择标准是“越小越好”,所以最差的情况就是“全胜”,也就是“胜率为1”;所以我们选择比1“还差”的数值 2 ;
“第i条数据” —— 第i行E列单元格 ÷ 第i行D列单元格
“打破记录” —— 第i行数据小于世界记录
其他不变,写成代码就是下面的样子:
这就是查找极值的套路,可以说是程序设计中最简单也最常用的套路之一。最后杨老师希望初学编程的同学思考一个问题:在本文的套路中,进入循环之前,为什么要把“世界纪录”设置为“比理论最差值再差一点”,而不是“理论最差值”呢?希望初学者多多思考。