简单动态规划 climbing-stairs

题目描述


You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?


分析:f(n)=f(n-2)+f(n-1)。

超时递归算法:复杂度2^n

public class Solution {
    public int climbStairs(int n) {
        if(n<0) return -1;
        if(n==1) return 1;
        if(n==2) return 2;
        return climbStairs(n-1)+climbStairs(n-2);
         
    }
}
普通:复杂度O(n)

public class Solution {
    public int climbStairs(int n) {
        if(n<0) return -1;
        if(n==1) return 1;
        if(n==2) return 2;
        int pre=1;
        int res=2;
        int t;
        for(int i=3;i<=n;i++){
            t=res;
            res=res+pre;
            pre=t;
        }
        return res;
         
    }
     
}

矩阵:O(logn)

public class Solution {
    public int climbStairs(int n) {
        if(n<0) return -1;
        if(n==1) return 1;
        if(n==2) return 2;
        int t = n-2;
        int[][] mat={{1,1},{1,0}};
        int[][] res={{1,0},{0,1}};
        //i>=0不行,0往右移动一位还是0
        for(int i=t;i!=0;i>>=1){
            if((i&1)!=0) res=mult(res, mat);
            mat=mult(mat, mat);
        }
        return 2*res[0][0]+res[1][0];
         
    }
     
     
    //矩阵乘法
    @SuppressWarnings("unused")
    private int[][] mult(int[][] matA,int[][] matB){
        int row = matA.length;
        int col = matB[0].length;
        int t = matA[0].length;//计算目标矩阵每一位,要做的乘法次数,第一个矩阵的列或第二个矩阵的行
        int[][] res = new int[row][col];
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                //目标矩阵的res[i][j];
                for(int k=0;k<t;k++){
                    res[i][j]+=(matA[i][k]*matB[k][j]);
                }
            }
        }
        return res;
    }
     
     
}

对比:

package com.lp;
public class Solution {
	/*
	 * [f(n),f(n-1)] = [f(n-1),f(n-2)]*[{1,1},{1,0}]
	 * [f(n-1),f(n-2)] = [f(n-2),f(n-3)]*[{1,1},{1,0}]
	 * ……
	 * [f(n),f(n-1)] = [f(2),f(1)]*[{1,1},{1,0}]^n-2
	 * 
	 * 所以答案f(n)就是f(2)*res[0][0]+f(1)*res[1][0];
	 * 转化为求:[{1,1},{1,0}]^n-2。。矩阵乘法
	 */
    public int climbStairs(int n) {
    	if(n<0) return -1;
    	if(n==1) return 1;
    	if(n==2) return 2;
    	int t = n-2;
    	int[][] mat={{1,1},{1,0}};
    	int[][] res={{1,0},{0,1}};
    	//i>=0不行,0往右移动一位还是0
    	for(int i=t;i!=0;i>>=1){
    		if((i&1)!=0) res=mult(res, mat);
    		mat=mult(mat, mat);
    	}
    	return 2*res[0][0]+res[1][0];
        
    }
    
    
    //矩阵乘法
    @SuppressWarnings("unused")
	private int[][] mult(int[][] matA,int[][] matB){
    	int row = matA.length;
    	int col = matB[0].length;
    	int t = matA[0].length;//计算目标矩阵每一位,要做的乘法次数,第一个矩阵的列或第二个矩阵的行
    	int[][] res = new int[row][col];
    	for(int i=0;i<row;i++){
    		for(int j=0;j<col;j++){
    			//目标矩阵的res[i][j];
    			for(int k=0;k<t;k++){
    				res[i][j]+=(matA[i][k]*matB[k][j]);
    			}
    		}
    	}
    	return res;
    }
    
    
    
    
    public static void main(String[] args) {
		Solution solution = new Solution();
		Long startLong=System.currentTimeMillis();
		System.out.println(solution.climbStairs(50000000));
		System.out.println("矩阵算法消耗时间:");
		System.out.println(System.currentTimeMillis()-startLong);
	}
}

输出:

223038178
矩阵算法消耗时间:
1

package com.lp;
public class Test {
    public int climbStairs(int n) {
        if(n<0) return -1;
        if(n==1) return 1;
        if(n==2) return 2;
        int pre=1;
        int res=2;
        int t;
        for(int i=3;i<=n;i++){
            t=res;
            res=res+pre;
            pre=t;
        }
        return res;
         
    }
    
    public static void main(String[] args) {
		Test solution = new Test();
		Long startLong=System.currentTimeMillis();
		System.out.println(solution.climbStairs(50000000));
		System.out.println("消耗时间:");
		System.out.println(System.currentTimeMillis()-startLong);
	}
     
}

输出:

223038178
消耗时间:
57


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值