算法题--动态规划

224 阅读3分钟

算法框架

# 初始化 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.矩阵覆盖

分析:构成第n块只有两种情况:

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的类似.最大子序和

思路:每次维护两个变量:st(当前的非负子序和,它努力超过当前最大子序和),maxsum(当前最大子序和)

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;
    }
};