70、难度简单:
题意:一个楼梯有 n 个台阶,你的每一步有两种选择,一次性跨2个台阶或1个台阶。求有多少种不同方法爬完楼梯。
注意:给定 n 是一个正整数,非0非负
方法一:数学
class Solution {
public int climbStairs(int n) {
double sqrt_5 = Math.sqrt(5);
double fib_n = Math.pow((1 + sqrt_5) / 2, n + 1) - Math.pow((1 - sqrt_5) / 2,n + 1);
return (int)(fib_n / sqrt_5);
}
}
裴波那契数列:斐波那契数列指的是这样一个数列:
这个数列从第3项开始,每一项都等于前两项之和
上述图中的公式就是求解第n项值为何的公式,此公式前提:
结合这道题:楼梯总阶数n对应裴波那契数列的第n+1项的n+1,而一共的通过方法对应该项的数值
原理:
当总阶数为1时,对应裴波那契第1+1=2项数值为1,即方法只有一种就是跨一步
当总阶数为2时,对应第2+1=3项值为2,即方法有两种,跨两个1步或跨一个2步
前两项恰好满足本题要求
拿4层台阶举例子。首先考虑怎么下第一脚,一步还是两步:
一步:剩下三步。那么剩下的三步能怎么走,也是按之前走出来的三步怎么走来进行;
两步:剩下两步。那么剩下的两步能怎么走,也是按之前走出来的两步怎么走来进行;
f(4) = f(3) + f(2)
剩下的同理
方法二:动态规划:
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
本问题其实常规解法可以分成多个子问题,爬第 n 阶楼梯的方法数量,等于 2 部分之和:
(1)爬上 n-1 阶楼梯的方法数量。因为再爬 1 阶就能到第 n 阶
(2)爬上 n-2 阶楼梯的方法数量,因为再爬 2 阶就能到第 n 阶
278、难度简单:
题意:题传入参数 n (代表1、2、3、…、n),然后我们通过调用题目帮我们写好的方法bool isBadVersion(version)来判断这 n 个数中哪些是错误的。我们需要找出第一个(最早出现的)错误的版本。
要求:尽量减少对调用 API(isBadVersion方法) 的次数
方法一:二分查找
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int left = 1, right = n;
while (left < right) { // 循环直至区间左右端点相同
int mid = left + (right - left) / 2; // ※ 防止计算时溢出
if (isBadVersion(mid)) {
right = mid; // 答案在区间 [left, mid] 中
} else {
left = mid + 1; // 答案在区间 [mid+1, right] 中
}
}
// 此时有 left == right,区间缩为一个点,即为答案
return left;
}
}
原理:两个指针 left 和 right,先求出它们的中间值 mid,若为错误的那就将 right 赋值为 mid,否则将 left 赋值为 mid。
也就是区间的左右两点都是错误的版本,并且一旦确认为错误后就不会改变除非存在更靠内侧的错误版本。
最终两点归一就是所求值