总结leetcode75中的一维动态规划 算法题解题思路。
上一篇:力扣75------回溯
力扣75------一维动态规划
- [1 第 N 个泰波那契数](#1 第 N 个泰波那契数)
- [2 使用最小花费爬楼梯](#2 使用最小花费爬楼梯)
- [3 打家劫舍](#3 打家劫舍)
- [4 多米诺和托米诺平铺](#4 多米诺和托米诺平铺)
- [1- 4解题总结](#1- 4解题总结)
1 第 N 个泰波那契数
题目:
cpp
泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
题解:
动态规划。按照公式进行迭代。这题的特点是,如何不使用临时变量而只用3个变量进行迭代。
cpp
class Solution {
public:
int tribonacci(int n) {
if (n==0) return 0;
if (n<3) return 1;
double n0 = 0, n1 = 1, n2 = 1;
for (int i = 0; i <= n - 3; ++i) {
n2 = n0 + n1 + n2;
n1 = n2 - n1 - n0;
n0 = n2 - n1 - n0;
/*
while (n2 > pow(2, 31)) {
n2 -= pow(2, 31);
}
while (n1 > pow(2, 31)) {
n1 -= pow(2, 31);
}
*/
}
return n2;
}
};
2 使用最小花费爬楼梯
题目:
cpp
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。
一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
题解1:题目是想找到一种方法,使得爬完这个楼梯的费用最少。如果一个人想爬到楼梯上面去,最后就只有2种可能 ,从第cost.size-1 向上走一步到达;从第cost.size-2 向上走2步到达。那么,只要算出分别爬到第cost.size-1和第cost.size-2所需的费用,然后再选择较小的那一个,即为所求结果。
所以可以从第1个台阶开始算,算出一个人爬到这个台阶的费用,然后往上递推计算即可。
cpp
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
vector<int> result(cost.size(), 0);
result[0] =cost[0];
result[1] = cost[1];
for (int i = 2; i < cost.size(); ++i) {
result[i] = result[i - 1] > result[i - 2] ? result[i - 2] + cost[i] : result[i - 1] + cost[i];
}
return min(result[cost.size() - 1], result[cost.size() - 2]);
}
};
题解2:
同题解1。但是空间复杂度更低。因为我们只是需要最终结果,所以只需要2个变量 来递推就行,不需要一个vector
。
cpp
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
//vector<int> result(cost.size(), 0);
int result0 = cost[0], result1 = cost[1], tmp = 0;
for (int i = 2; i < cost.size(); ++i) {
tmp = result1;
result1 = result1 > result0 ? result0 + cost[i] : result1 + cost[i];
result0 = tmp;
}
return min(result0, result1);
}
};
3 打家劫舍
题目:
cpp
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约
因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统
会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能
够偷窃到的最高金额。
题解:
动态规划。与题目2类似,只是这次需要3个变量来递推。
问题分析 :直接看这一排房屋的最后两个,如果想要偷最多,最后这两个房子肯定是要偷一个的。可以证明,如果这两个房子都不偷,得到的金额为a,那么a+最后一个房子的钱,肯定是大于a的。
思路分析 :为了确定它是偷最后一个还是偷倒数第二个,还需要知道倒数第三个和倒数第四个要不要偷。所以可以从第一个开始计算,然后递推求解。
解题思路:从第一个房间开始递推,计算偷窃该房子后,金额是多少。设当前房子为i,如果进去偷,则第i-1是不能偷的。那么是2种可能,偷完第i-3后直接偷第i;偷完第i-2后,直接偷第i。具体选择依据偷完它们后哪个金额更大来决定。
cpp
class Solution {
public:
int rob(vector<int>& cost) {
if (cost.size() < 2) return cost[0];
int result0 = 0, result1 = cost[0], result2 = cost[1], tmp = 0;
for (int i = 2; i < cost.size(); ++i) {
tmp = result2;
result2 = result1 > result0 ? result1 + cost[i] : result0 + cost[i];
result0 = result1;
result1 = tmp;
}
return max(result2, result1);
}
};
4 多米诺和托米诺平铺
题目:
cpp
有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 "L" 的托米诺形。两种形状都
可以旋转。
给定整数 n ,返回可以平铺 2 x n 的面板的方法的数量。返回对 109 + 7 取模 的值。
平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻
单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。
题解:
动态规划。对于每一列,如果其左边均铺满瓷砖,右侧未铺,则其总共有4种状态:
一个正方形都没有被覆盖,记为状态0;
只有上方的正方形被覆盖,记为状态1;
只有下方的正方形被覆盖,记为状态2;
上下两个正方形都被覆盖,记为状态3。
通过递推迭代,即可得到结果。
cpp
class Solution {
public:
const long long mod = 1e9 + 7;
int numTilings(int n) {
vector<vector<long long>> dp(n + 1, vector<long long>(4));
dp[0][3] = 1;
for (int i = 1; i <= n; i++) {
dp[i][0] = dp[i - 1][3];
dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % mod;
dp[i][2] = (dp[i - 1][0] + dp[i - 1][1]) % mod;
dp[i][3] = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3]) % mod;
}
return dp[n][3];
}
};
1- 4解题总结
题目特点:一个位置的状态,受到之前位置的影响。
解题方法:从第一个位置开始,计算出它达到每个状态的得分,然后递推下一个位置。
解题重点1:如何将题目转化为状态递推问题。
解题重点2:如何用更少的变量来递推。