动态规划简单

动态规划四个步骤:1、确认最后一步,以及子问题 2、转移方程  3、初始值,边界条件 4、遍历方向(从左到右,从上到下)

最大子序和

给定一个数组,找到一个具有最大和的连续数组,返回其最大值。首先是一段连续的数组,这就涉及到了该位置上的数字选还是不选,要是最大的和,如果dp[i-1]>0的话,那么dp[i]=dp[i-1] + num[i],如果都dp[i-1] < 0 的2话,num[i]加上一个负数是小于它本身的,所以dp[i[ = num[i],而这道题我们需要知道前面一位的dp值,那么我们应该初始化第一位dp[0]=num[0],这里只需要循环到n-1,即可。所以申请空间也只需要n个,最后循环遍历dp数组获取最大值。时间复杂度O(n)。

func maxSubArray(nums []int) int {
    max := nums[0]
    for i := 1; i < len(nums); i++ {
        if nums[i]+nums[i-1] > nums[i] {
            nums[i] += nums[i-1]
        }
        if nums[i] > max {
            max = nums[i]
        }
    }
    return max
}
 1 class Solution {
 2 public:
 3     int maxSubArray(vector<int>& nums) {
 4         int ans = nums[0];
 5         for (int i = 1; i < nums.size(); i++) {
 6             if (nums[i-1] > 0) {
 7                 nums[i] = nums[i] + nums[i-1];
 8             }
 9             ans = max(ans, nums[i]);
10         }
11         return ans;
12     }
13 };
View Code

按摩师

根据题意,给定一个数组。如果选择第i位数,那么他的前面后面的数都不能选,找到最大值的一个集合,返回最大值。这道题同样的方式,确定最终问题,也就是最后一个数,我们有两种情况,①如果我们选择了最后一位,所以就存在 dp[i][0]=d[i-1][1]+num[i],②如果我们不选那就是dp[i][1] = max(dp[i-1][0],dp[i-1][1]),对于子问题同样的存在选与不选两种情况。所以需要一个初始值,dp[0][0] = num[0], dp[0][1] = 0,(0表示选,1表示不选)。因为求最大值,遍历方向就是从左到右,顺序遍历。

 1 class Solution {
 2 public:
 3     int massage(vector<int>& nums) {
 4         int n = (int)nums.size();
 5         if (n == 0) {
 6             return 0;
 7         }
 8         int dp0 = nums[0], dp1 = 0;
 9         for (int i = 1; i < n; i++) {
10             int tp0 = dp1 + nums[i];
11             int tp1 = max(dp0, dp1);
12             dp0 = tp0;
13             dp1 = tp1;
14         }
15         return max(dp0, dp1);
16     }
17 };
View Code
func massage(nums []int) int {
    n := len(nums)
    dp := make([][]int, n)
    if n == 0 {
        return 0
    }
    for index := range dp {
        dp[index] = make([]int, 2)
    }
    dp[0][0] = nums[0]
    dp[0][1] = 0
    max := func(a, b int) int{
        if a > b {
            return a
        }else {
            return b
        }
    }
    for i :=1; i < n; i++ {
        dp[i][0] = dp[i-1][1] + nums[i]
        dp[i][1] = max(dp[i-1][0], dp[i-1][1])
    }
    return max(dp[n-1][0],dp[n-1][1])
}

除数博弈

一种博弈题,在最优解下先手是否必赢,通过规律可以发现,当数为偶数时,爱丽丝必赢,当为奇数时,鲍勃必赢。因为只有2才能最后到达1,而需要到达4,当爱丽丝面临着偶数情况时,可以选择最优解快速让自己到达2,而面对奇数时,能被奇数求余为0的只能是奇数,而当奇数减去奇数时,变为了偶数,然后当鲍勃开始时,则面临着和爱丽丝一样的情况,偶数时可以选择最优情况快速到达2,所以当数为偶数是返回true,当为奇数时返回false。

func divisorGame(N int) bool {
    return N%2 == 0
}

买卖股票的最佳时机

根据题意,你只能买进和卖出一次,求出能获得的最大利润。对于最后一天,我们应该判断是买进还是卖出,因为是求出最大值,如果我们这时候卖出则需要与前一次卖出进行对比,得到最大值,即dp[i][0] = (dp[i-1][0],dp[i-1][1]+num[i]),如果我们买进则需要选择在这之前最小的即dp[i][1] = min(dp[i-1][1],num[i]),因为我们要算获利多少,所以买进的时候应该为负数,此时我们就需要买进时的最大值。dp[i][1] = min(dp[i-1][1],-num[i]。前一次同样面临着相同的子问题。再来是初始值问题,dp[0][0] = 0,dp[0][1] = -num[i],第一次卖出是0,第一次买入为-num[0]。最后返回答案dp[len-1][0].

func maxProfit(prices []int) int {
    n := len(prices)
    if n < 2 {
        return 0
    }
    dp := make([][]int, n) 
    for index := range dp {
        dp[index] = make([]int, 2)
    }
    dp[0][0] = 0
    dp[0][1] = -prices[0]
    max := func(a, b int) int {
        if a < b {
            return b
        }
        return a
    }
    for i := 1; i < n; i++ {
        dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i])
        dp[i][1] = max(dp[i-1][1],-prices[i])
    }
    return dp[n-1][0]
}
 1 class Solution {
 2 public:
 3     int maxProfit(vector<int>& prices) {
 4         int n = prices.size();
 5         if (n == 0) {
 6             return 0;
 7         }
 8         int dp0 = 0, dp1 = -prices[0];
 9         for (int i = 1; i < n; i++) {
10             int tp0 = max(dp0, dp1+prices[i]);
11             int tp1 = max(dp1, -prices[i]);
12             dp0 = tp0;
13             dp1 = tp1;
14         }
15         return dp0;
16     }
17 };
View Code

使用最小花费爬楼梯

根据题意可以知道,我们每次爬楼梯可以爬一步,也可以爬两步,初始位置可以在索引0和1上,那么我们考虑到达最后的花费有两种情况dp[i-1]+cost[i-1], dp[i-2]+cost[i-2], 我们需要求最小值所以dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]),初始值就是dp[0] = 0,dp[1] = 1。注意这里是要到最顶层,即最小值为dp[n]。

func minCostClimbingStairs(cost []int) int {
    n := len(cost)
    ans := make([]int, n+1)
    ans[0] = 0
    ans[1] = 0
    if n == 0 {
        return 0
    }
    if n == 1{
        return cost[0]
    }
    min := func(a, b int) int {
        if a > b {
            return b
        }
        return a
    }
    if n == 2 {
        return min(cost[0], cost[1])
    }
    for i :=2; i <= n; i ++ {
        ans[i] = min(ans[i-1]+cost[i-1], ans[i-2]+cost[i-2])
    }
    return ans[n]
}
 1 class Solution {
 2 public:
 3     int minCostClimbingStairs(vector<int>& cost) {
 4         int n = cost.size();
 5         if (n <= 1) {
 6             return 0;
 7         }
 8         vector<int> dp(n + 1, 0);
 9         dp[0] = 0;
10         dp[1] = 0;
11         for(int i = 2; i <= n; i++) {
12             dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]);
13         }
14         return dp[n];
15     }
16 };
View Code

 

posted @ 2020-10-11 16:23  cxylsy  阅读(135)  评论(0编辑  收藏  举报
页脚Html代码