这是一篇介绍C语言经典编程问题——喝汽水的详解,包含三种解决问题的实现思路、思考方式以及不同代码,也以时间空间复杂度的方式做了简单比较。
原问题
喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元可以买到多少汽水?
方法一——递归角度
思考
1元可以买到1瓶汽水和一个空瓶,2个空瓶可以再次获得1瓶汽水,再次获得一个空瓶,由此联想到递归实现: 递归条件的判断,只有两个瓶时只能换1瓶汽水,故退出递归的条件应是瓶数为2时,返回1;而一个空瓶时已不能兑换汽水,故每次喝完汽水后都会至少剩余1个空瓶,1瓶也可作为退出递归条件,返回0;
代码实现
递归函数
//递归函数,通过判断瓶数决定返回值
int cokenum(int x)
{
if (x == 1)
{
return 0;
}
//只有两个瓶返回1
else if (x == 2)
{
return 1;
}
//偶数瓶进入递归
else if (x % 2 == 0)
{
return x / 2 + cokenum(x / 2);
}
//奇数瓶进入递归,需加上剩下的一个瓶
else
{
return x / 2 + cokenum(x / 2 + 1);
}
}
主函数
int main()
{
int x = 0;
scanf("%d", &x);
printf("%d", x + cokenum(x));//汽水数+汽水瓶数
return 0;
}
全代码
#include<stdio.h>
//根据钱值判断汽水数目
//1元一瓶—>原值 两空瓶换汽水—>汽水数/2
//递归解决,
int cokenum(int x)
{
//只有一个瓶返回0;
if (x == 1)
{
return 0;
}
//只有两个瓶返回1
else if (x == 2)
{
return 1;
}
//偶数瓶进入递归
else if (x % 2 == 0)
{
return x / 2 + cokenum(x / 2);//换一半的汽水,还有一半的空瓶
}
//奇数瓶进入递归,需加上剩下的一个瓶
else
{
return x / 2 + cokenum(x / 2 + 1);//换一半汽水,再加上剩下的一个瓶
}
}
int main()
{
int x = 0;
scanf("%d", &x);
printf("%d", x + cokenum(x));
return 0;
}
代码较为冗余,思考的复杂直接将代码复杂化了,时间复杂度及空间复杂度都分别达到了O(logn)。
方法二——循环角度
思考
1元换1瓶汽水还有一个空瓶,也就是说,金钱数目-1时,瓶子数目+1,汽水数目+1; 而瓶子数等于2时,可以再换1瓶汽水,故,瓶子数目-2时,汽水数目+1,由此知可以通过循环判断,有瓶子就换汽水。
代码实现
#include<stdio.h>
int main()
{
int x = 0;
int coke = 0, bottle = 0;
scanf("%d", &x);
while (x)
{
x--;
coke++;
bottle++;
if (bottle == 2)//瓶子数等于2时就换汽水,换了之后瓶数-1;
{
bottle--;
coke++;
}
}
printf("%d", coke);
return 0;
}
通过循环判断,时间复杂度不变,而空间复杂度优化为O(1)。
方法三——数学角度
思考
通过金钱数判断,1元换1瓶汽水,2元换3瓶汽水,3元换5瓶汽水,4元换7瓶汽水······ 简单观察可知,金钱对应的汽水数为一个等差数列: 1——1,2——3,3——5,4——7,5——7······ 规律为 汽水数=2×金钱数-1;
代码实现
#include<stdio.h>
int main()
{
int x = 0;
scanf("%d", &x);
printf("%d", 2 * x - 1);
}
由此可知,当实际问题与数学相结合之后,复杂的问题会变得更为清晰,此时时间复杂度与空间复杂度都为O(1)。