14天阅读挑战赛,努力是为了不平庸
通过前面的内容我们已经知道了,什么是算法,以及算法的复杂性、如何比较两个算法的好坏,那么今天我们我们就从一道真正的算法题目入手,来实践它吧。有位伟人曾经说过,实践出真知。这个题目叫做一棋盘的麦子,它是一道经典的算法题,来源于一个著名的故事:
有一个古老的传说,一位国王的女儿不幸落水,水中有很多鳄鱼,国王情急之下下令:“ 如果有谁能够活着把公主救上来,那么就把女儿嫁给他。 ” 但是很多人看着水里的鳄鱼还是选择纷纷退让,就在这时,有一个年轻的勇士挺身而出,冒着生命危险把公主救了上来,但是国王看到此人是个穷小子,家里一清二白的,就想反悔,不把女儿嫁给他,于是故意说:“ 除了女儿,你要什么都可以。 ”勇士说:“ 好吧我只要一棋盘的麦子。您在第 1 个格子里放上 1 粒麦子,在第 2 个格子里放上放上 2 粒,在第 3 个格子里放上 4 粒,在第 4 个格子里放 8 粒。以此类推,每一个格子里麦子的粒数都是前一格麦子粒数的两倍。把这 64 个格子放满了就行,我就要这么多。”
国王一听,这不有手就行,顿时仰天大笑,认为这个人的要求很容易满足,随即满口答应,然后吩咐大臣去照办了。但是后面发现,即使把全国所有的麦子都拿来,也不能够按要求完全放满这 64 个格子。国王非常无奈,因为无法满足勇士的要求,只好把自己的宝贝女儿嫁给了他。
题目解析
那么你知道如果要按勇士的要求放满棋盘上的 64 个格子一共需要多少粒麦子吗?我们可以来计算一下,首先,把每一个格子里需要放的麦子粒数加起来,其总和为,则:
①
对 ① 进行处理,两边乘以2,则:
②
用式子 ② 减去 ①,得出:
据专家统计,每颗麦粒的平均重要约为 41.9 毫克,这些麦粒的总重量则为:
(毫克)
大概约等于 7729 000 (亿千克),假设全世界人口按 77 亿计算,那么每个人差不多可以分到 100 吨的麦子,这么多的麦子,吃到世界末日也不一定吃的完
代码实现
C
/** checkerboardGrainProblem.c -- 计算棋盘上的麦粒问题*/
#include <stdio.h>
#include <math.h>
int main(int argc, const char *argv[])
{
/*
程序初始化,因为数据量比较大,所以
使用无符号的 long long int 类型,
定义 i 用于遍历每个格子,sum 用于记录总的麦粒数
*/
unsigned long long int i, sum = 0L;
for (i = 1L; i <= 64L; i++)
{
// 循环计算每个格子上的麦粒数,并累加
unsigned long long int r = pow(2L, i - 1L);
sum += r;
}
// 打印输出计算得到的麦粒数
printf("%llu\n", sum);
return 0;
}
Java
/**
* 计算棋盘上的麦粒问题
*/
public class CheckerboardGrainProblem {
public static void main(String[] args) {
// 初始化 sum 为 0
BigDecimal sum = new BigDecimal("0.0");
// 循环计算每个格子上的麦粒数并相加
for (double i = 1.0D; i <= 64.0D; i++) {
sum = sum.add(BigDecimal.valueOf(Math.pow(2.0D, i - 1D)));
}
System.out.println("sum = " + sum);
}
}
这是一种最简单的解法,但是时间复杂度相对较高,所有还有一种更好的解法:
C
/** checkerboardGrainProblem.c -- 计算棋盘上的麦粒问题*/
#include <stdio.h>
#include <math.h>
int main(int argc, const char *argv[])
{
// 计算并输出总和
printf("sum = %.0f\n", pow(2.0d, 64.0d) - 1.0d);
return 0;
}
Java
/**
* 计算棋盘上的麦粒问题
*/
public class CheckerboardGrainProblem {
public static void main(String[] args) {
// 计算并输出总和
System.out.println("sum = " + BigDecimal.valueOf(Math.pow(2.0D, 64.0D) - 1.0D));
}
}
如果使用循环处理上面的题目需要大量的计算,我们称这样的函数为爆炸式增量函数。想一想,如果算法的复杂度是 会怎么样?想也知道,这样的程序很有可能会爆掉内存。就像我们经常看见有些算法本地调试没有问题,运行一段时间也还好,但是就是在关键的时候宕机(shutdown)。
所以在设计算法的时候,我们需要考虑到时间复杂度的问题,哪种算法更适合当前场景,尽可能优化代码,实现最佳的时间复杂度。关于什么是算法的复杂性?如何对算法的性能进行比较?如何对算法的复杂度进行分析?这些问题可以参考我上一篇文章:14天阅读打卡-02-算法的复杂性
往期打卡
技术文章
1、14天阅读打卡-01-初识算法
2、14天阅读打卡-02-算法的复杂性
3、14天阅读打卡-03-一棋盘的麦子
4、14天阅读打卡-04-斐波那契数列
冷知识
因为一切原因或意外而导致的死机,一些数据库服务器的死锁,服务器的某些服务停止运行而导致计算机无法正常工作,都可以称为宕机。