算法其实并不是那么遥不可及,很多程序员都觉得自己不懂算法,其实他们每天都在使用着。例如,把提供给用户的数据按照某一个维度排一个序;对用户的请求做一个去重。这些都是算法。
在面试中,我们常常会被面试到算法题,甚至被要求写代码。一方面是考察你的算法基础,更重要地是看你分析问题的能力。
今天我们来看一个这么一个问题:
大家都玩过手机游戏,会根据你最后的分数,给你3颗星,或者2颗星,或者1颗星。今天我们有这样的一个游戏,首先,我们有若干个器皿,每个器皿里面都没有细胞,我们有下面两种操作:
1.往某一个器皿中加入一个新的细胞。
2.用一个特殊射线让所有器皿中的所有细胞一分为二。(假设细胞都可以分裂,且不会死掉)。
现在,我们一开始有n个器皿,通过一个系列的操作,我们让器皿中的细胞个数分别为a[1],a[2],a[3]..a[n]。如果用户用最少的操作完成目标,我们给他3颗星,现在我们想知道最少需要多少次操作。
例子1: n = 2, a = {1, 2} 结果为3
例子2: n = 2, a = {4, 8} 结果为5步,使用3次操作1,变成{1, 2}, 然后进行2次操作2。
思考:
很多人,一看到这个题目,一般都立马萌了。脑海中划过千万只草泥马,不对,千万种算法,都对应不上,然后GG。
干货1:问题分解,把简单的问题简单化!
我们先不做这个题目,我们来想一想另外一个问题。有两个操作, 加1 或者 乘以2, 如何把0变成x。例如 8 = (0 + 1) * 2 * 2 * 2。
然后我们再想一个问题,1个x,可以进行两个操作, 减1 或者 除以2(如果是2的倍数),如何更快地把x 变成 0. 例如15 : (((15 - 1 ) / 2 - 1) / 2 - 1) / 2 - 1 = 0.
不难发现,我们要尽量地使用乘除,少用加减。于是乎,我们有了这么一个算法。
至此,我们解决了这么一个子问题。我们知道了每个目标数需要多少次加法,多少次乘法。
让我们来看另外一个问题,假如我们知道每个数需要多少次加法跟乘法,我们总共需要多少次呢?我们来回头看一看规则。
1.往某一个器皿中加入一个新的细胞。
2.照射一个特殊射线让所有器皿中的所有细胞一分为二。(假设可以无穷分裂)。
我们发现,加法是不能共享的,但是乘法可以。我们举个例子来说明一下, a = {2, 4, 10},分别需要1,2,3次乘法和都需要{1,1,2}加法。
{0,0,1} a[3] 加 1
{0,0,2} 使用乘法
{0,1,2} a[2]加1
{0,2,4} 使用乘法
{1,2,5} a[1],a[3]加1
{2,4,10}使用乘法
总结:
经过上面的分析,这个题目的结果就是先求出每一个数的加法跟乘法的数量,然后最后结果为total{add} + max{mul},即总的加法次数与最大的乘法次数。
给大家留两个思考题,可以在评论中留言:
为什么要尽量用乘法。 有没有多用加法,少乘法的情况
如果题目换成加法共享,乘法独占,这个题目又应该怎么做?
欢迎大家关注我的头条号,也可以关注我的微信公众号(ddpcyh),会提供算法学习资料,一起来学习算法吧。