喝汽水问题详解

时间:2023-02-24 15:02:24

这是一篇介绍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)。