算法框架
# 初始化 base case
dp[0][0][...] = base
# 进行状态转移
for 状态1 in 状态1的所有取值:
for 状态2 in 状态2的所有取值:
for ...
dp[状态1][状态2][...] = 求最值(选择1,选择2...)
明确 base case -> 明确「状态」-> 明确「选择」 -> 定义 dp 数组/函数的含义。
1.斐波那契数列
链接:https://www.nowcoder.com/questionTerminal/c6c7742f5ba7442aada113136ddea0c3?f=discussion
来源:牛客网
public class Solution {
public int Fibonacci(int n) {
int preNum=1;
int prePreNum=0;
int result=0;
if(n==0)
return 0;
if(n==1)
return 1;
for(int i=2;i<=n;i++){
result=preNum+prePreNum;
prePreNum=preNum;
preNum=result;
}
return result;
}
}
2.跳台阶
链接:https://www.nowcoder.com/questionTerminal/8c82a5b80378478f9484d87d1c5f12a4?answerType=1&f=discussion
来源:牛客网
public class Solution {
public int JumpFloor(int target) {
if(target <= 2){
return target;
}
int pre2 = 1, pre1 = 2;
for (int i = 3; i <= target; i++){
int cur = pre2 + pre1;
pre2 = pre1;
pre1 = cur;
}
return pre1;
}
}
3.变态跳台阶
sollution1:dp写法
链接:https://www.nowcoder.com/questionTerminal/22243d016f6b47f2a6928b4313c85387?answerType=1&f=discussion
来源:牛客网
import java.util.*;
public class Solution {
public int JumpFloorII(int target) {
if (target <= 2) {
return target;
}
int[] dp = new int[target + 1];
Arrays.fill(dp, 1); //初始化每一种都可以直接从 0 跳到 n
dp[0] = 0; //从 0 跳到 0 为 0 种,因为 n = 0,没法跳
for (int i = 2; i <= target; i++) {
for (int j = i - 1; j >= 1; j--) {
dp[i] += dp[j]; //第 n 个状态是由前 n - 1 种状态推导出来,就是累加!
}
}
return dp[target];
}
}
sollution2:找规律变成数学问题
易知 f(n)=f(n-1)+f(n-2)+……f(1) f(n-1)=f(n-2)+……f(1) 两式相减得f(n)=2f(n-1)
class Solution {
public:
int jumpFloorII(int number) {
return 1<<(number-1);
}
};
4.矩阵覆盖
1.到达n-2块的时候,剩两块,就横着放两块。
2.到达n-1块的时候,剩一块,竖着覆盖上去就行了。
public:
int rectCover(int number) {
if(number<=2)return number;
int pre1=1,pre2=2;
int result;
for(int i=3;i<=number;i++){
result=pre1+pre2;
pre1=pre2;
pre2=result;
}
return result;
}
};
5.连续子数组最大和
链接:https://www.nowcoder.com/questionTerminal/459bd355da1549fa8a49e350bf3df484?answerType=1&f=discussion
来源:牛客网
public int FindGreatestSumOfSubArray(int[] array) {
int max = array[0];
for (int i = 1; i < array.length; i++) {
array[i] += array[i - 1] > 0 ? array[i - 1] : 0;
max = Math.max(max, array[i]);
}
return max;
}
5的类似.最大子序和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int maxsum=nums[0];
int st=0;
for(int i=0;i<nums.size();i++){
st=max(nums[i],st+nums[i]);
maxsum=max(maxsum,st);
}
return maxsum;
}
};
6.leecode516 最长回文子序列
class Solution {
public int longestPalindromeSubseq(String s) {
int slen=s.length();
//dp数组的含义是在i到j的字符串中最长的回文子序列
int[][] dp=new int[slen][slen];
//初态:单个字符都是回文的
for(int i=0;i<slen;i++){
dp[i][i]=1;
}
for(int i=slen-1;i>=0;i--){
for(int j=i+1;j<slen;j++){
//有两种情况:1.i和j的字符相同,易理解2.不同,就算i+1到j和i到j-1的dp,取较大值,所以要知
//道三个位置的dp值,所以要倒着遍历
if(s.charAt(i)==s.charAt(j)){
dp[i][j]=dp[i+1][j-1]+2;
}else{
dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1]);
}
}
}
return dp[0][slen-1];
}
}
7.leecode121 买卖股票最佳时期
说白了就是给一个数组,要求找出两个数之间的最大差值,且后一个数要比前一个数大
用动态规划
维护两个值:minprice,和最大利润maxp
minprice最开始要设为很大的值
class Solution {
public:
int maxProfit(vector<int>& prices) {
int inf = 1e9;
int minprice=inf;
int maxp=0;
for(int i=0;i<prices.size();i++){
minprice=min(minprice,prices[i]);
maxp=max(maxp,prices[i]-minprice);
}
return maxp;
}
};