费式数列有关问题

费式数列问题

古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?

 

程序中的bearAge为3时,即为题目中的3个月,也可以为任意大于等于2个月后生。

 

package algorithm.fibonacci;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class RabbitService {

	class Rabbit {

		public int age;

		public Rabbit() {
			this.age = 1;
		}

		public Rabbit(int age) {
			this.age = age;
		}
	}

	/*
	 * 面向对象方法
	 */
	public void printRabbit(int month, int bearAge) {

		if (month > 0) {
			long start = System.currentTimeMillis();
			// 保存每个月份的兔子数目
			long[] rabbitNumbersArray = new long[month];

			// rabbitList保存所有的兔子,在第一个月有一对大兔子
			Rabbit bigRabbit = new Rabbit();
			List<Rabbit> rabbitList = new ArrayList<Rabbit>();
			rabbitList.add(bigRabbit);

			rabbitNumbersArray[0] = rabbitList.size();

			// 从第二个月开始计算,如果兔子刚生下来age为1,则age为3时兔子才能生兔子
			for (int currentMonth = 2; currentMonth <= month; currentMonth++) {
				int lastMonthRabbitNumber = rabbitList.size();
				for (int i = 0; i < lastMonthRabbitNumber; i++) {
					Rabbit rabbit = rabbitList.get(i);
					rabbit.age++;
					if (rabbit.age >= bearAge) {
						rabbitList.add(new Rabbit());
					}
				}
				rabbitNumbersArray[currentMonth - 1] = rabbitList.size();
			}
			long end = System.currentTimeMillis();
			System.out.println("1月到" + month + "月的兔子数目为:"
					+ Arrays.toString(rabbitNumbersArray) + ",使用时间为"
					+ (end - start));
		} else {
			System.out.println("输入月份必须大于0");
		}
	}

	/*
	 * 作用递归方法计算费式数列,当兔子生育月不为3时,也可以计算
	 */
	public void printRabbit2(int month, int bearAge) {
		if (month > 0) {
			long start = System.currentTimeMillis();
			long[] rabbitNumbersArray = new long[month];
			for (int i = 1; i <= month; i++) {
				rabbitNumbersArray[i - 1] = fibonacci(i, bearAge);
			}
			long end = System.currentTimeMillis();
			System.out.println("1月到" + month + "月的兔子数目为:"
					+ Arrays.toString(rabbitNumbersArray) + ",使用时间为"
					+ (end - start));
		} else {
			System.out.println("输入月份必须大于0");
		}
	}

	private int fibonacci(int n, int bearAge) {
		if (n < bearAge) {
			return 1;
		} else {
			return fibonacci(n - 1, bearAge)
					+ fibonacci(n - (bearAge - 1), bearAge);
		}
	}

	/*
	 * 根据费式数列特点,当前值为前两项之和
	 */
	public void printRabbit3(int month, int bearAge) {
		if (month > 0) {
			long start = System.currentTimeMillis();
			long[] rabbitNumbersArray = new long[month];
			int currentMonth = 0;
			for (currentMonth = 1; currentMonth < bearAge; currentMonth++) {
				rabbitNumbersArray[currentMonth - 1] = 1;
			}
			for (currentMonth = bearAge; currentMonth <= month; currentMonth++) {
				rabbitNumbersArray[currentMonth - 1] = rabbitNumbersArray[currentMonth
						- bearAge]
						+ rabbitNumbersArray[currentMonth - 2];
			}
			long end = System.currentTimeMillis();
			System.out.println("1月到" + month + "月的兔子数目为:"
					+ Arrays.toString(rabbitNumbersArray) + ",使用时间为"
					+ (end - start));
		} else {
			System.out.println("输入月份必须大于0");
		}
	}

	public static void main(String[] args) {
		RabbitService service = new RabbitService();
		int bearAge = 3;
		service.printRabbit(20, bearAge);
		service.printRabbit2(20, bearAge);
		service.printRabbit3(20, bearAge);
	}
}

 

输出:

1月到20月的兔子数目为:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765],使用时间为6
1月到20月的兔子数目为:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765],使用时间为2
1月到20月的兔子数目为:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765],使用时间为0