相关题目
Leetcode 70、509、1137、746、198、740
题目特点
①典型的动态规划问题
②当前状态的求取仅与前几个相邻状态有关
结题步骤
(设当前状态与相邻a个状态有关)
①确定当前状态与相邻a个状态关系(状态转移方程)
②初始化前a个状态
③遍历数组不断更新求取
相关题目分析
Leetcode 70 爬楼梯
①到达第 i
阶有两种方式,从第 i-1
阶爬一阶或者从第 i-2
阶爬两阶,因此到达第 i
阶的方法数等于到达第 i-1
阶和第 i-2
阶的方法数之和。
状态转移方程:
allWays = onestepBefore + twostepBefore;
②初始化onestepBefore和twostepBefore
int onestepBefore = 2 //到达第 2 阶的方法数(可以直接跳两步,或者一步一步走)。
int twostepBefore =1 //到达第 1 阶的方法数(只有一种方法,即直接走一步)。
完整解题代码:
class Solution {
public:
int climbStairs(int n) {
if(n == 1) return 1;
if(n == 2) return 2;
int onestepBefore = 2;
int twostepBefore = 1;
int allWays = 0;
for(int i =3;i<=n;i++){
allWays = onestepBefore+twostepBefore;
twostepBefore = onestepBefore;
onestepBefore = allWays;
}
return allWays;
}
};
Leetcode 509 斐波那契数列
①状态转移方程
fib = oneBefore + twoBefore;
②初始化onebefore和twoBefore
int oneBefore = 1 //斐波那契数列的第 1 项。
int twoBefore = 0 //斐波那契数列的第 0 项。
完整解题代码:
class Solution {
public:
int fib(int n) {
if(n == 0) return 0;
if(n == 1) return 1;
int oneBefore = 1;
int twoBefore = 0;
int fib = 0;
for(int i = 2;i<=n;i++){
fib = oneBefore+twoBefore;
twoBefore = oneBefore;
oneBefore = fib;
}
return fib;
}
};
Leetcode 1137 第N个泰波那契数
①状态转移方程:
tribonacci = oneBefore+twoBefore+threeBefore;
②初始化oneBefore、twoBefore和threeBefore
int oneBefore = 1 //泰波那契序列的第 2 项。
int twoBefore = 1 //泰波那契序列的第 1 项。
int threeBefore = 0 //泰波那契序列的第 0 项。
完整解题代码:
class Solution {
public:
int tribonacci(int n) {
if(n == 0) return 0;
if(n == 1|| n == 2) return 1;
int oneBefore = 1;
int twoBefore = 1;
int threeBefore = 0;
int tribonacci = 0;
for(int i = 3;i<=n;i++){
tribonacci = oneBefore+twoBefore+threeBefore;
threeBefore = twoBefore;
twoBefore = oneBefore;
oneBefore = tribonacci;
}
return tribonacci;
}
};
Leetcode 746 使用最小花费爬楼梯
①到达第 i
阶楼梯的最小花费是到达第 i-1
阶楼梯的最小花费加上第 i-1
阶的花费,与到达第 i-2
阶楼梯的最小花费加上第 i-2
阶的花费之间的较小值。
状态转移方程:
minCost = min(oneStepBefore + cost[i-1], twoStepBefore + cost[i-2])
②初始化
int oneStepBefore = 0 //到达第 1 阶楼梯的最小花费(因为可以选择从第 0 阶或第 1 阶开始,所以花费为 0)。
int twoStepBefore = 0 //到达第 0 阶楼梯的最小花费(不需要花费)。
完整解题代码:
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size()+1; //楼梯顶第为n+1阶
if(n == 1||n == 2) return 0;
int oneStepBefore = 0;
int twoStepBefore = 0;
int minCost = 0;
for(int i = 2;i<n;i++){
minCost = min(oneStepBefore+cost[i-1],twoStepBefore+cost[i-2]);
twoStepBefore = oneStepBefore;
oneStepBefore = minCost;
}
return minCost;
}
};
Leetcode 198 打家劫舍
①到达第 i
个房屋时能偷到的最大金额,要么是到达第 i-1
个房屋时的最大金额(不偷第 i
个房屋),要么是到达第 i-2
个房屋时的最大金额加上第 i
个房屋的金额(偷第 i
个房屋)。
状态转移方程:
max_rob = max(max_rob, pre_rob + nums[i])
②初始化
int max_rob = nums[0] //到达第 1 个房屋时能偷到的最大金额(只有一种方法,即偷第 1 个房屋)。
int pre_rob = 0 //到达第 0 个房屋之前能偷到的最大金额(没有房屋可偷,所以金额为 0)。
完整解题代码:
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
int max_rob = nums[0];
int pre_rob = 0;
for (int i = 1; i < n; i++) {
int tmp = max_rob;
max_rob = max(max_rob, pre_rob + nums[i]);
pre_rob = tmp;
}
return max_rob;
}
};
Leetcode 740 删除并获得点数
①删除并获得点数到当前数字 i
为止的最大点数,要么是保持之前的最大点数(不删除当前数字),要么是前一个非相邻数字的最大点数加上当前数字的总点数(删除当前数字)。
(与打家劫舍题目唯一的不同点在于需要将数组排序成有序数组)
状态转移方程:
max_count = max(max_count, pre_max + get_count(nums, i))
②
int max_count = get_count(nums, nums[0]) //删除并获得点数到第一个数字为止的最大点数(只删除第一个数字)。
int pre_max = 0 //删除并获得点数到第一个数字之前(即没有删除任何数字)的最大点数。
完整解题代码:
class Solution {
public:
int get_count(vector<int>& nums, int num) {
int n = nums.size();
int j = 0;
for (int i = 0; i < n; i++) {
if (nums[i] == num) j++;
}
return num * j;
}
int deleteAndEarn(vector<int>& nums) {
sort(nums.begin(),nums.end());
int n = nums.size();
int max_count = get_count(nums, nums[0]);
int pre_max = 0;
for (int i = nums[0]+1; i <= nums[n-1]; i++) {
int tem = max_count;
max_count = max(max_count, pre_max + get_count(nums,i));
pre_max=tem;
}
return max_count;
}
};