爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

解法:
参考:程序员小灰 https://mp.weixin.qq.com/s/3h9iqU4rdH3EIy5m6AzXsg
其实爬楼梯是最简单的动态规划问题,因为只有单一变量。此问题可以转为斐波那契数列来解,也即是:
状态转移方程:F(n) = F(n-1) + F(n-2)
最优子结构:F(n-1) 和 F(n-2)
边界:F(1) =1, F(2)=2

由此,分别得到以下解法以及优化解法

/**
	 * 基础版递归解法
	 * 由此,可以得到一个二叉树
	 * 二叉树的节点数即是需要计算的次数
	 * 时间复杂度O(n`2)
	 * @param n
	 * @return
	 */
	public int climbStairs(int n) {
        if(n<1) {
        	return 0;
        }else if (n==1) {
			return 1;
		}else if (n==2) {
			return 2;
		}
        return climbStairs(n-1)+climbStairs(n-2);
    }

可以发现,很多值是重复计算了。比如n==5时,n=3就重复计算了两次,是浪费的。其实只需要计算O(n)次。所以,可以使用缓存,缓存之前的计算结果。降低时间复杂度。
代码如下:

public int climbStairs(int n) {
        if(n<1) {
        	return 0;
        }else if (n==1) {
			return 1;
		}else if (n==2) {
			return 2;
		}
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(1, 1);
        map.put(2, 2);
        return climbStairs(n, map);
    }
	public int climbStairs(int n, Map<Integer, Integer> map) {
		if(map.containsKey(n)) {
			return map.get(n);
		}else {
			int value = climbStairs(n-1, map)+climbStairs(n-2, map);
			map.put(n, value);
			return value;
		}
	}

目前空间复杂度为O(n),从这方面入手,继续优化。目前的思路是为计算F(n),依次计算F(n-1),F(n-1)…2,1 。将沙漏倒过来思考,也就是
已知:F(1),F(2),那可以算出来F(3)
已知:F(2),F(3),那可以算出来F(4)
所以,想要计算n,其实只需要记录n-1,n-2的step,就可以实现了。空间复杂度从O(n)到O(1)
代码如下:

/**
 * 时间复杂度O(n)
 * 空间复杂度O(1)
 * 最优解
 * @param n
 * @return
 */
public int climbStairs(int n) {
        if(n<1) {
        	return 0;
        }else if (n==1) {
			return 1;
		}else if (n==2) {
			return 2;
		}
        int n_1=2,n_2=1;
        int temp =0;
        for(int i=3;i<=n;i++) {
        	temp = n_1 + n_2;
        	
        	n_2 = n_1;
        	n_1 = temp;
        }
        return temp;
    }
点赞