规律--汽水问题

以汽水问题为例,向程序员致敬,并缅怀自己的编程岁月。以下的所有函数,都是数学表达式,不是编码实现。

简单

首先从最简单的场景出发,看看汽水问题的思路。现有问题描述如下:

规则:喝汽水,1瓶汽水1元,集齐2个空瓶才能换一瓶汽水。

前提:现在有20元

问题:到底可以喝多少瓶汽水

一般来说,第一反应肯定是基于前提,按照规则去拆解问题。思路如下:

  1. 20元,获得20瓶汽水。喝掉20瓶,剩下20个空瓶

  2. 20个空瓶,可换10瓶汽水。喝掉10瓶,剩下10个空瓶

  3. 10个空瓶,可换5瓶汽水。喝掉5瓶,剩下5个空瓶

  4. 4个空瓶,可换2瓶汽水。喝掉2瓶,得到3个空瓶(5个空瓶中4个去换汽水,剩下1)

  5. 2个空瓶,可换1瓶汽水。喝掉1瓶,得到2个空瓶

  6. 2个空瓶,可换1瓶汽水。喝掉1瓶,得到1个空瓶

  7. 最终是20+10+5+2+1+1=39瓶,且剩下一个空瓶

img

整体来说就是分解问题,然后逐个穷举:

  1. 用钱能买到多少瓶汽水,喝掉产生空瓶,这是直接运算能得到的。

  2. 空瓶基于规则换汽水,喝掉再产生空瓶,循环穷举计算

在现有场景下,很多人认为是可行的思路。甚至部分业务程序员,直接就这么编码,导致后期出现性能问题。20元需要1次计算和5次内部循环,下面我们来看看钱多一点的的场景

普通

普通场景的规则是一致的,但是钱多了很多。问题描述如下:

规则:喝汽水,1瓶汽水1元,集齐2个空瓶才能换一瓶汽水。

前提:现在有2111元

问题:到底可以喝多少瓶汽水

2110转换成2进制,是100000111110。那么按照上面的方法,至少需要1次计算和11次循环(11次位移)。忽略其他的因素,耗时几乎翻倍。即便这个情况能解决,那么百万元呢?

此时应该尝试去寻找规律,思路如下(我的高中数学老师应该会很开心):

  1. 利用数学理想,等价于寻找数字的规律(喝汽水瓶数)

  2. 列举出足够多的数字

  3. 尝试寻找规律

  4. 举例验证规律

这个场景中非常的简单,数列如下:

1、3、5、7、9…

通过数学归纳法,得到规律是2n-1。

然后试试前面的20元,刚好是39。再试试13,也是25。

即,n元能喝汽水瓶数:

f(n) = 2n-1(n>0)

从算法维度来衡量,这个时间复杂程度就是O(1),钱的大小不影响。

中等

问题描述如下:

规则:喝汽水,1瓶汽水6元,3个空瓶换一瓶汽水。

前提:已知24元,可以喝6瓶汽水

问题:为何可以喝6瓶?假设有x元,可以喝y瓶汽水?

这个其实分为两个问题,第一个问题是第二个问题的先决条件。

先按照分解问题穷举的思路,发现24元可买4瓶,喝4瓶->换1瓶并喝掉,剩下2空瓶。此时只有向老板借一瓶汽水,喝完有三个空瓶。将三个空瓶给老板,视为还一瓶汽水。所以,可以喝6瓶。

第一个问题,让我们知道可以借瓶子。再延伸一下,就是空瓶是有价值的。

利用等价转换法分析,可知道一份汽水的价值为4元,一个空瓶价值1元。

所以,y = └x/4┘(x除以4的结果,向下取整)

这里只讨论逻辑,上面的结论实际情况下是很可笑的。假如我刚好有4元,如下操作后可用可以喝到一瓶汽水:

  1. 4元向老板买两个空瓶

  2. 再向老板借一瓶汽水喝掉,得到1个空瓶

  3. 3个空瓶给老板,兑换汽水,还给老板

困难

问题描述如下:

规则:喝汽水,x元一瓶,现有促销搞活动:新批次的汽水,y个空瓶可以换一瓶汽水(x、y>=1)。

前提:汽水价格不因促销而有所变动,针对空瓶换的汽水,品牌商会对店老板进行补贴

问题:店老板进货z瓶,品牌商实际应该给几瓶(补贴损失)(Z>y)

这个其实就是困难情况的一般化,继续使用等价转换法:

一份汽水实际价值 = x – x/y

实际进货汽水总数 f(z) = └ z * x / (x-x/y) ┘

汽水实际价格是原有价格的倍数(x / (x-x/y)),对应的进货量也要乘以对应的倍数。

极难

前面,价格都是比较好算的1元,改为3元。问题描述如下:

规则:喝汽水,1瓶汽水3元,集齐3个空瓶才能换一瓶汽水。

前提:现在有n元

问题:到底可以喝多少瓶汽水

和前面类似,先列举出足够多的数据:

如何寻找数字的规律,我认为数学的范畴。反正既然价格是3,就用3倍数进行表示,寻找规律。

一般前面的数字,规律比较难找。以9为分界线(3*3=9,9以后才会出现空瓶换汽水),分段标出。所以规律总结,数学表达如下:

数字分为奇数和偶数,应该可以继续优化,尝试用2的倍数来表达9以后的值:

由于习惯,使用2n-1方式表达奇数。如果用前面的方法,规律不太明显。考虑到是为了从奇偶性角度简化计算,直接从n出发,转换为结果:

img

地狱

问题描述如下:

规则:喝汽水,x元一瓶,y个空瓶可以换一瓶汽水(x、y>=1)。

前提:现有n元(n>=x)

问题:如果可以借汽水,可以喝多少瓶汽水?如果不能,可以喝多少瓶?

可以借汽水,就很简单了:

一份汽水 = x – x/y

可以喝汽水总数 f(n) = └ n/(x-x/y) ┘(向下取整)

不能借汽水,就无法使用等价转换。参考上一个场景,规律如下:


  目录