第十三天
70 爬楼梯
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
基本方法
考虑到达最后一级阶梯的方法数,有两种方式,一种是直接一步跨两级阶梯,另外一种是一步跨一级。
因此,如果将爬n
级阶梯得总方法数记为f(n)
,那么根据加法原理,存在以下递推关系:
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
f(n)=f(n-1)+f(n-2)
f(n)=f(n−1)+f(n−2)
由于原题数据量较小,可以考虑直接打表即可。
class Solution {
public int climbStairs(int n) {
int[] res = {1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903};
return res[n - 1];
}
}
矩阵快速幂
依据递推关系式,可以得到
$$
\left{
\begin{array}{lr}
f(n+1)=f(n)+f(n-1)\
f(n)=f(n)
\end{array}
\right.
因
此
,
可
以
得
出
以
下
矩
阵
关
系
:
因此,可以得出以下矩阵关系:
因此,可以得出以下矩阵关系:
\begin{bmatrix}
f(n+1)\
f(n)
\end{bmatrix}
\begin{bmatrix}
1 & 1\
1 & 0
\end{bmatrix}
\begin{bmatrix}
f(n)\
f(n-1)
\end{bmatrix}
\begin{bmatrix}
1 & 1\
1 & 0
\end{bmatrix}^n
\begin{bmatrix}
f(1)\
f(0)
\end{bmatrix}
$$
198 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
方法
考虑到第i
间房间为止,能够偷到的最大数量的金额。**定义dp[i]
表示小偷从第0
间房间开始偷,偷到第i
间房间能够偷到的最大金额。**那么对于第i
间房间,存在两种情况:
- 偷第
i
间房间 - 不偷第
i
间房间
对于第一种情况,如果偷了第i
间房间,那么第i-1
间房间就不能够偷了,此时dp[i] = dp[i - 2] + nums[i]
。
对于第二种情况,如果选择不偷第i
间房间,那么其值应该和前一个dp
值相同,即dp[i] = dp[i - 1]
综上,可以得到以下状态转移方程:
d
p
[
i
]
=
m
a
x
{
d
p
[
i
−
2
]
+
n
u
m
s
[
i
]
,
d
p
[
i
−
1
]
}
dp[i]=max\{dp[i-2]+nums[i],dp[i-1]\}
dp[i]=max{dp[i−2]+nums[i],dp[i−1]}
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) return nums[0];
else if (nums.length == 2) return Math.max(nums[0], nums[1]);
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for (int i = 2; i < dp.length; ++i){
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[nums.length - 1];
}
}
120 三角形最小路径和
给定一个三角形 triangle
,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标i
,那么下一步可以移动到下一行的下标i
或i + 1
。
方法
考虑在位置(i,j)
时,应该做的选择,存在两种方式可以到达该位置:
- 从
(i-1,j-1)
到达 - 从
(i-1,j)
到达
由于题目中考虑的是最小值,因此只要取两者中的较小值,同时注意边界的判断即可。状态转移方程为:
d
p
[
i
]
[
j
]
=
m
i
n
{
d
p
[
i
−
1
]
[
j
−
1
]
,
d
p
[
i
−
1
]
[
j
]
}
+
n
u
m
s
[
i
]
[
j
]
dp[i][j]= min\{dp[i-1][j-1],dp[i-1][j]\}+nums[i][j]
dp[i][j]=min{dp[i−1][j−1],dp[i−1][j]}+nums[i][j]
class Solution {
public static int MAXVALUE = 10001 * 200;
public int minimumTotal(List<List<Integer>> triangle) {
if (triangle.size() == 1) return triangle.get(0).get(0);
int[][] dp = new int[triangle.size()][];
for (int i = 0; i < triangle.size(); ++i){
dp[i] = new int[triangle.get(i).size()];
}
dp[0][0] = triangle.get(0).get(0);
for (int i = 1; i < dp.length; ++i){
for (int j = 0; j <= i; ++j){
int superLayer1 = (j - 1 >= 0) ? dp[i - 1][j - 1] : MAXVALUE;
int superLayer2 = (i - 1 >= j) ? dp[i - 1][j] : MAXVALUE;
dp[i][j] = Math.min(superLayer1, superLayer2) + triangle.get(i).get(j);
}
}
int ans = MAXVALUE;
for (int j = 0; j < dp[dp.length - 1].length; ++j)
ans = Math.min(ans, dp[dp.length - 1][j]);
return ans;
}
}