动态规划
核心思想:
将大问题划分小问题去解决,就是将历史数据存起来的一种算法,而存历史数据的就是数组,可以是一维,也可以是二维。
三大步骤:
步骤一:定义数组dp[i](或dp[i][j])是什么含义,一般求什么设什么。
步骤二:寻找数组元素间的关系推导式,换句话说,dp[i]是由dp[i-1]或dp[i-2]如何转换而来。例如dp[i][j]一定与dp[i-1][j-1],dp[i][j-1],dp[i-1][j]有关系。这一步是最难的。
步骤三:数组初始化,也就是边界初始化。因为后面的dp[n]由前面的推导而来,首先要赋值初始值才能得出结果。
案例一:
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
分析:
定义dp[i] 为爬上i阶的路径,dp[i]可以由i-1阶或i-2阶跳上来。初始化dp[1]=dp[0]=1;跳上1或0阶路径为1.
代码实现:
dp[1]=dp[0]=1;
for(int i=2;i<=n;i++)
dp[i]=dp[i-2]+dp[i-1];
案例二:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/house-robber
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:
定义dp[i]为打劫所获取的最大金额。dp[i]由是打劫前一个房屋(dp[i-1])和是打劫当前房屋(dp[i-2]+nums[i])推导而来,值得注意的是要进行特判,最开始打劫第一个,还是第二个。初始化dp[0]=nums[0].
代码实现:
dp[0]=nums[0];
int n=nums.size();
for(int i=1;i<n;i++){
if(i==1)
dp[1]=max(nums[0],nums[1]);
else{
dp[i]=max(dp[i-1],dp[i-2]+nums[i]);
}
}