能用打表法的题目特征
- 问题返回值不太多,可以用 hardcode 的方式列出,作为程序的一部分
- 一个大问题解决时,底层频繁使用规模不大的小问题的解,如果小问题的返回值满足条件 1,可以把小问题的解列成一张表,作为程序的一部分。
- 打表找规律
这样的大概有四成可以使用打表法
打表法步骤
- 写出暴力解法
- 多次调用暴力解法,将输入和出入打印出来。
- 从结果中找规律,根据归纳出的规律直接返回结果
小虎买苹果
小虎去附近的商店买苹果,奸诈的商贩使用了捆绑交易,只提供 6 个每袋和 8 个每袋的包装,包装不可拆分。可是小虎现在只想购买恰好 n 个苹果,小虎想购买尽量少的袋数方便携带。如果不能购买恰好 n 个苹果,小虎将不会购买。输入一个整数 n ,表示小虎想购买的苹果,返回最少使用多少袋子。如果无论如何都不能正好装下,返回 -1.
暴力解法
分析
最终要求的结果是最少使用多少个袋子。那么尽可能多使用能装 8 苹果的大袋子。
最多能使用 bg8 = int( n / 8 ) 大袋子,剩下的苹果(rest = n - int(n/8) * 8)使用小袋子(6个苹果)去装,
如果剩下的苹果刚好能够装满 k 个小袋子(rest % 6 ==0),那么返回 bg8 + int( rest / 6 )。
如果 rest % 6 !=0,说明不能用 int(n/8) 个大袋子,可以尝试 int(n/8) - 1个大袋子,然后再尝试小袋子。
24 是 8 和 6 最大公约数。如果大袋子装完后,剩余苹果大于 24,比如 rest = 27,那么 rest = 24 + 3,剩余的 24 可以用 3 个大袋子,而现在没有用大袋子,说明在之前用了 3 个大袋子后,小袋子不能装满,已经计算过了,不需要再计算了。
# 如果剩余苹果 rest 可以装满小袋子,返回小袋子树
# 否则返回 -1
def min_bag_base6(rest):
return int(rest / 6) if rest % 6 == 0 else -1
def min_bags(apple):
if apple < 0: return -1
bg6 = -1
bg8 = int(apple / 8)
rest = apple - 8 * bg8
while bg8 >= 0 and rest < 24:
rest_use6 = min_bag_base6(rest)
if rest_use6 != -1:
bg6 = rest_use6
break
bg8 -= 1
rest = apple - 8 * bg8
return -