码迷,mamicode.com
首页 > 其他好文 > 详细

网易2016笔试(2)

时间:2016-08-01 15:56:14      阅读:273      评论:0      收藏:0      [点我收藏+]

标签:

有n个信封,包含n封信,现在把信拿出来,再装回去,要求每封信不能装回它原来的信封,问有多少种装法?

给定一个整数n,请返回装发个数,为了防止溢出,请返回结果Mod 1000000007的值。保证n的大小小于等于300。

测试样例:2   返回 1

           一开始我以为是卡特兰数问题:卡特兰数应用
          考虑半天,但是也无法列出卡特兰数的公式。安静下来发现,h(0)=h(1)=0,不满足卡特兰数条件。于是乎就想请教大神。大神给了个思路:
       计算f(n),假设1,2,3,4,......n。那么n若放在位置i,可以分两种情况考虑。i放在位置n和i不放在位置n。为什么这么考虑呢?因为如果i放在n,那么剩下就是f(n-2),否则的话就是f(n-1)。第一种情况你很容易理解,i和n都放好了,剩下的就是n-2个数不放在原来的信封里。但是i如果不放在n位置,剩下n-1个数,其中i放哪都可以啊,和题目中每个信封不放在原信封条件不同啊。很好,i是可以放在任何位置,但前提假设了这种情况是i不放在n位置。这样这n-1个数,除了i,其余的限制是不放在原信封,i的限制是不放在n位置。所以等价这其实就是f(n-1)。
        问题到这,用递归计算就太简单了。代码如下:
        
int countWays(int n) {
        // write code here
        if(n<2)return 0;
        if(n==2)return 1;
        return (n-1)*(countWays(n-1)%1000000007+countWays(n-2)%1000000007);
    }
      
       问题求得的结果没得问题,但是时间使用超过3000ms,远远超过限制时间。
           但也可以猜想到,就是上述代码重复计算了太多值。于是乎,就改用循环。代码如下:
       
int countWays(int n) {
        // write code here
       int a=0;
       int b=1;
        if(n<=1)return a;
        if(n==2)return b;
        long result;
        long x=0;
        long y=1;
        for(int i=3;i<=n;i++)
            {
            result=(i-1)*(x+y)%1000000007;
            x=y;
            y=result;
        }
        return result;
    }
      这样就很好了,根据n的大小,从头到尾计算一遍,直至f(n)。
      总结:在一个序列上递归就很容易产生重复计算的问题,造成代码效率不高。同时一开始考虑问题总想着套路,这样并不好。有思路有解法才能利用公式等工具解决问题。先想解法,再看是不是公式,再解题。

网易2016笔试(2)

标签:

原文地址:http://blog.csdn.net/yutianxin123/article/details/52085753

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!