F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)
指这样一个数列:1、1、2、3、5、8、13、21、34、……
和:2^(n-1)
爬楼梯70
有 N 阶楼梯,每次可以上一阶或者两阶,求有多少种上楼梯的方法。
定义一个数组 dp 存储上楼梯的方法数(为了方便讨论,数组下标从 1 开始),dp[i] 表示走到第 i 个楼梯的方法数目。
第 i 个楼梯可以从第 i-1 和 i-2 个楼梯再走一步到达,走到第 i 个楼梯的方法数为走到第 i-1 和第 i-2 个楼梯的方法数之和。
考虑到 dp[i] 只与 dp[i - 1] 和 dp[i - 2] 有关,因此可以只用两个变量来存储 dp[i - 1] 和 dp[i - 2],使得原来的 O(N) 空间复杂度优化为 O(1) 复杂度。
public int climbStairs(int n) {
if (n <= 2) {
return n;
}
int pre2 = 1, pre1 = 2;
for (int i = 2; i < n; i++) {
int cur = pre1 + pre2;
pre2 = pre1;
pre1 = cur;
}
return pre1;
}
爬楼梯
可以爬一级,可以爬两级,也可以爬n级`
public int JumpFloor{
return 1<<(target-1);
}
强盗抢劫198
抢劫一排住户,但是不能抢邻近的住户,求最大抢劫量。
定义 dp 数组用来存储最大的抢劫量,其中 dp[i] 表示抢到第 i 个住户时的最大抢劫量。
由于不能抢劫邻近住户,如果抢劫了第 i -1 个住户,那么就不能再抢劫第 i 个住户,所以
public int rob(int[] nums){
int pre2=0,pre1=0;
for(int i=0;i<nums.length;i++){
int cur=Math.max(pre2+nums[i],pre1);
pre2=pre1;
pre1=cur;
}
return pre1;
}
强盗在环形街区抢劫
第一个房和最后一个房是紧挨的,不能抢劫相邻的房
public int rob(int[] nums){
if(nums==null||nums.length==0){
return 0;
}
int n=nums.length;
if(n==1){
return nums[0];
}
return Math.max(rob(nums,0,n-2),rob(nums,1,n-1));
}
private int rob(int[] nums,int first,int last){
int pre2=0,pre1=0;
for(int i=first;i<=last;i++){
int cur=Math.max(pre2+num[i],pre1);
pre2=pre1;
pre1=cur;
}
reutrn pre1;
}
信件错排
NowCoder每天要给很多人发邮件。有一天他发现发错了邮件,把发给A的邮件发给了B,把发给B的邮件发给了A。于是他就思考,要给n个人发邮件,在每个人仅收到1封邮件的情况下,有多少种情况是所有人都收到了错误的邮件?即没有人收到属于自己的邮件。
当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用dp[n]表示,那么dp[n-1]就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.
第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;
第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有dp[n-2]种方法;⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有dp[n-1]种方法;
public int erroNum(int n){
if(n=0)
return 0;
if(n=1)
return 0;
int []dp=new int [n+1];
dp[0]=0;
dp[1]=0;
dp[2]=1;
for(int i=3;i<=n;i++){
dp[i]=(i-1)*(dp[i-1]+dp[i-2]);
}
return dp[n];
}
母牛生产
题目描述:假设农场中成熟的母牛每年都会生 1 头小母牛,并且永远不会死。第一年有 1 只小母牛,从第二年开始,母牛开始生小母牛。每只小母牛 3 年之后成熟又可以生小母牛。给定整数 N,求 N 年后牛的数量。
public int c1(int n){
if(n<0) return 0;
if(n==1||n==2||n==3) return n;
return c1(n-1)+c1(n-3);
}