递归的Fibonacci在数羊

一、由数羊引起的

有一道经典的面试题是这样的。

题目:一头母羊的寿命是5年,它会在第2年底和第4年底各生下一头母羊,第5年底死去,
问一开始农场有1头母羊,N年后,农场会有多少只母羊?

(假设没有公羊也会生羊,而且只只生母羊,不要较真 - -!)

乍一看不知所云,其实慢慢分析so easy!


思路:
年数      羊的个数      备注
1            1             1只羊
2            2=1+1      生1只
3            2             不生
4            4=2+2      第1只在第4年生,第2只在第2年生
5            3=4-1       第1只样死去
6            6=3+3      第2只在4年生,第3只在第2年生,第4只在第2年生
7            5=6-1       第2只样死去
8            10=5+5     第3只在第4年生,第4只在第4年生,
9            8=10-2     第3只和第4只死去
10          16=8+8     继续生...
规律:奇数年是1 2 3 5 8 的斐波那契数列
      偶数年是2 4 6 10 16的斐波那契数列

所以我们首先得了解Fibonacci数列。

二、Fibonacci数列

【题目】一列数的规则如下: 1、1、2、3、5、8、13、21、34...... 求第30位数是多少, 用递归算法实现。

/// <summary>
/// 一列数的规则如下: 1、1、2、3、5、8、13、21、34...... 求第30位数是多少, 用递归算法实现
/// </summary>
/// <param name="pos">第几位</param>
/// <returns>返回该位置处的数字</returns>
public int Fib(int pos)
{
    if (pos <= 0)
    {
        return 0;
    }
    if (pos == 1)
    {
        return 1;
    }
    int result = Fib(pos - 1) + Fib(pos - 2);
    return result;
}

  


我们还可以将递归改为非递归。利用数组就可实现。比方说:

/// <summary> 
/// 非递归算法计算斐波那契数,速度要比递归快 
/// </summary> 
/// <param name="pos">第几位</param> 
/// <returns>返回该位置处的数字</returns> 
public int GetNumAtPos(int pos) 
{ 
    int result = 0; 
    int[] arr = new int[1000 * 1000];

    arr[0] = 1; 
    arr[1] = 1;

    for (int i = 2; i < pos; i++) 
    { 
        arr[i] = arr[i - 2] + arr[i - 1]; 
    }

    result = arr[pos - 1];

    return result; 
} 

  

三、农场养羊问题

了解了Fibonacci数列之后,我们继续回到数羊的问题上。根据分析的思路可以写出如下一种实现方式:

public class Fibonacci 
{ 
    /// <summary> 
    /// 题目:一头母羊的寿命是5年,它会在第2年底和第4年底各生下一头母羊,第5年底死去, 
    /// 问一开始农场有1头母羊,N年后,农场会有多少只母羊?(假设只生母羊,不要较真 - -!) 
    /// </summary> 
    /// <remarks> 
    /// 思路: 
    ///年数      羊的个数      备注 
    ///1            1            1只羊 
    ///2            2=1+1        生1只 
    ///3            2            不生 
    ///4            4=2+2        第1只在第4年生,第2只在第2年生 
    ///5            3=4-1        第1只样死去 
    ///6            6=3+3        第2只在4年生,第3只在第2年生,第4只在第2年生 
    ///7            5=6-1        第2只样死去 
    ///8            10=5+5        第3只在第4年生,第4只在第4年生, 
    ///9            8=10-2        第3只和第4只死去 
    ///10            16=8+8        继续生... 
    ///规律:奇数年是1 2 3 5 8 的斐波那契数列 
    ///      偶数年是2 4 6 10 16的斐波那契数列 
    /// </remarks> 
    /// <param name="year"></param> 
    /// <returns></returns> 
    public int CountSheep(int year) 
    { 
        int result = 0; 
        // 奇数年 
        if (year%2==1) 
        { 
            year = (year + 1) / 2; // 折半 
            result = EvenSum(year); 
            return result; 
        } 
        // 偶数年 
        if (year%2==0) 
        { 
            year = year / 2; // 折半 
            result = OddSum(year); 
            return result; 
        } 
        return result; 
    }

    /// <summary> 
    /// 奇数年的Fibonacci数 
    /// </summary> 
    /// <param name="year">第几年</param> 
    /// <returns>羊的个数</returns> 
    private int EvenSum(int year) 
    { 
        int num = 0; 
        if (year <= 0) 
        { 
            return 0; 
        } 
        if (year==1) 
        { 
            return 1; 
        } 
        if (year==2) 
        { 
            return 2; 
        }

        num = EvenSum(year - 1) + EvenSum(year - 2);

        return num; 
    }

    /// <summary> 
    /// 偶数年的Fibonacci数 
    /// </summary> 
    /// <param name="year">第几年</param> 
    /// <returns>羊的个数</returns> 
    private int OddSum(int year) 
    { 
        int num = 0; 
        if (year<=0) 
        { 
            return 0; 
        } 
        if (year==1) 
        { 
            return 2; 
        } 
        if (year==2) 
        { 
            return 4; 
        } 
        num = OddSum(year - 1) + OddSum(year - 2); 
        return num; 
    } 
}

  

测试方法如下:

static void Main(string[] args) 
{ 
	int result = 0;

	// 斐波那契方法测试 
	Fibonacci fib = new Fibonacci(); 
	//result = fib.Fib(30);

	// 非递归数组方法测试 
	//result = fib.GetNumAtPos(50);

	// 数羊测试 
	for (int i = 1; i <= 12; i++) 
	{ 
		result = fib.CountSheep(i); 
		Console.WriteLine("第 " + i + " 年羊的个数为:" + result); 
	}

	
	Console.ReadLine(); 
}

  

运行效果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值