动态规划:坐标型+序列

说明

例题leetcode上基本都可以找的到
若leetcode上题目要vip可以跑lintcode

入门题

零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104
仙人指路:题目题

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:

输入:coins = [2], amount = 3
输出:-1
示例 3:

输入:coins = [1], amount = 0
输出:0
示例 4:

输入:coins = [1], amount = 1
输出:1
示例 5:

输入:coins = [1], amount = 2
输出:2
在这里插入图片描述

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n=coins.size();
        int f[10010]={0};
        f[1]=INT_MAX;
        for(int i=1;i<=amount;i++)
        {
            f[i]=INT_MAX;
            for(int j=0;j<n;j++)
            if(i>=coins[j])
            {
                if(f[i-coins[j]]!=INT_MAX&&f[i-coins[j]]<f[i])
                f[i]=f[i-coins[j]]+1;
            }
        }
        return f[amount]==INT_MAX?-1:f[amount] ;
    }
};

不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?
提示:
1 <= m, n <= 100

示例 1:

输入:m = 3, n = 7
输出:28
示例 2:

输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向下
    示例 3:

输入:m = 7, n = 3
输出:28
示例 4:

输入:m = 3, n = 3
输出:6

不同路径练习题目在这里插入图片描述

class Solution {
public:
    int uniquePaths(int m, int n) {
        int f[110][110]={0};

        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(i==0||j==0) f[i][j]=1;
                else f[i][j]=f[i-1][j]+f[i][j-1];
            }
        }
        return f[m-1][n-1];
    }
};

跳跃游戏

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

1 <= nums.length <= 3 * 104
0 <= nums[i] <= 105

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        bool f[30000]={false};
        f[0]=true;
        int n=nums.size();
        for(int j=1;j<n;j++)// 枚举每个坐标点,判断是否可以由前面的坐标点到达;
        {
            for(int i=0;i<j;i++)
			{
				if(f[i]&&i+arr[i]>=j) //这个式子有一个前提i必须是可以到达的点 
				{
					f[j]=true;//当判断完第j个点可以到达时,即可以break;
					break;
				}
			}            
        }
        return f[n-1];
    }
};

当然可以优化下,时间复杂度可以讲到o(n),空间复杂度为o(1) ,可以设一个变量记录可以跳跃到的最大值点,点第j个点<最大值时,既可以return false;

坐标型动态规划

不同路径 II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

1 <= m, n <= 100
obstacleGrid[i][j] 为 0 或 1

示例 1:

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右
    示例 2:

输入:obstacleGrid = [[0,1],[0,0]]
输出:1
在这里插入图片描述

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& path) {
        int m=path.size();
        int n=path[0].size();
        int f[101][101]={0};
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(path[i][j]==1)
                f[i][j]=0;
                else
                {
                    if(i==0&&j==0) f[i][j]=1;
                    if(i>=1) f[i][j]=f[i-1][j];
                    if(j>=1) f[i][j]+=f[i][j-1];
                    cout<<f[i][j]<<" ";
                }
            }
            cout<<endl;
        }
        return f[m-1][n-1];
    }
};

粉刷房子

假如有一排房子,共 n 个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。

当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3 的正整数矩阵 costs 来表示的。

例如,costs[0][0] 表示第 0 号房子粉刷成红色的成本花费;costs[1][2] 表示第 1 号房子粉刷成绿色的花费,以此类推。

请计算出粉刷完所有房子最少的花费成本。

1 <= n <= 100
1 <= costs[i][j] <= 20

示例 1:

输入: costs = [[17,2,17],[16,16,5],[14,3,19]]
输出: 10
解释: 将 0 号房子粉刷成蓝色,1 号房子粉刷成绿色,2 号房子粉刷成蓝色。
最少花费: 2 + 5 + 3 = 10。
示例 2:

输入: costs = [[7,6,2]]
输出: 2
题目链接
在这里插入图片描述

class Solution {
public:
    int minCost(vector<vector<int>>& costs) {
        int n=costs.size();
        int f[101][3]={0};
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<3;j++)
            {
                if(j==0) f[i][j]=min(f[i-1][1],f[i-1][2])+costs[i-1][j];
                if(j==1) f[i][j]=min(f[i-1][0],f[i-1][2])+costs[i-1][j];
                if(j==2) f[i][j]=min(f[i-1][1],f[i-1][0])+costs[i-1][j];
            }
        }
        int res=INT_MAX;
        for(int i=0;i<3;i++)
        {
            res=min(res,f[n][i]);
        }
         return res;
    }
};

解码方式

一条包含字母 A-Z 的消息通过以下映射进行了 编码 :

‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,“11106” 可以映射为:

“AAJF” ,将消息分组为 (1 1 10 6)
“KJF” ,将消息分组为 (11 10 6)
注意,消息不能分组为 (1 11 06) ,因为 “06” 不能映射为 “F” ,这是由于 “6” 和 “06” 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数 。

题目数据保证答案肯定是一个 32 位 的整数。

1 <= s.length <= 100

示例 1:

输入:s = “12”
输出:2
解释:它可以解码为 “AB”(1 2)或者 “L”(12)。
示例 2:

输入:s = “226”
输出:3
解释:它可以解码为 “BZ” (2 26), “VF” (22 6), 或者 “BBF” (2 2 6) 。
示例 3:

输入:s = “0”
输出:0
解释:没有字符映射到以 0 开头的数字。
含有 0 的有效映射是 ‘J’ -> “10” 和 ‘T’-> “20” 。
由于没有字符,因此没有有效的方法对此进行解码,因为所有数字都需要映射。
示例 4:

输入:s = “06”
输出:0
解释:“06” 不能映射到 “F” ,因为字符串含有前导 0(“6” 和 “06” 在映射中并不等价)。

在这里插入图片描述

class Solution {
public:
    int numDecodings(string s) {
        int f[101]={0};
        f[0]=1;
        int n=s.length();
        for(int i=1;i<=n;i++)
        {
            int t=s[i-1]-'0';
            if(t>=1&&t<=9) f[i]+=f[i-1];
            if(i>=2) {
                t=(s[i-2]-'0')*10+s[i-1]-'0';
                if(t>=10&&t<=26) f[i]+=f[i-2];
            }
        }
        return  f[n];
    }
};

最小路径和

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

1 <= m, n <= 200
0 <= grid[i][j] <= 100

示例 1:

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。
示例 2:

输入:grid = [[1,2,3],[4,5,6]]
输出:12

在这里插入图片描述

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m=grid.size(),n=grid[0].size();
        int f[200][200]={0};
        f[0][0]=grid[0][0];
        for(int i=1;i<m+n;i++)
        {
            if(i<m) f[i][0]=f[i-1][0]+grid[i][0];
            if(i<n) f[0][i]=f[0][i-1]+grid[0][i];
        }
        for(int i=1;i<m;i++)
            for(int j=1;j<n;j++)
            {
                f[i][j]=min(f[i-1][j],f[i][j-1])+grid[i][j];
            }
        return f[m-1][n-1];
    }
};

序列动态规划

比特位计数

给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

0 <= n <= 105
示例 1:

输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10
示例 2:

输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
题目

观察上面给的案例易得出f[i]=f[i>>1]+i%2;

class Solution {
public:
    vector<int> countBits(int n) {
         vector<int> ret;
         ret.resize(n+1);
         ret[0]=0;
         for(int i=1;i<=n;i++)
         {
             ret[i]=ret[i>>1]+i%2;
         }
        return ret;
    }
};

粉刷房子II

这里有n个房子在一列直线上,现在我们需要给房屋染色,共有k种颜色。每个房屋染不同的颜色费用也不同,你希望每两个相邻的房屋颜色不同

费用通过一个nxk 的矩阵给出,比如cost[0][0]表示房屋0染颜色0的费用,cost[1][2]表示房屋1染颜色2的费用。找到油漆所有房子的最低成本。

所有费用都是正整数

样例
样例1

输入:
costs = [[14,2,11],[11,14,5],[14,3,10]]
输出: 10
说明:
三个屋子分别使用第1,2,1种颜色,总花费是10。
样例2

输入:
costs = [[5]]
输出: 5
说明:
只有一种颜色,一个房子,花费为5
题目

这题目可以设最小值和次小值,进行标记,即可由时间复杂度O(nmm) 降到O(n*m)

class Solution {
public:
    /**
     * @param costs: n x k cost matrix
     * @return: an integer, the minimum cost to paint all houses
     */
    int minCostII(vector<vector<int>> &costs) {
        int n=costs.size();
        if(n==0) return 0;
        int m=costs[0].size();
        if(m==0) return 0;
        vector<vector<int>> f;
        f.resize(n+1);
        for(int i=0;i<=n;i++) f[i].resize(m+1);
        for(int i=1;i<=n;i++)
        {
            int min1=INT_MAX,min2=INT_MAX;
            int j1=0,j2=0;
            for(int k=0;k<m;k++)
            {
                if(f[i-1][k]<min1)
                {
                    min2=min1;
                    min1=f[i-1][k];
                    j2=j1;
                    j1=k;
                }
                else
                {
                    if(f[i-1][k]<min2)
                    {
                        min2=f[i-1][k];
                        j2=k;
                    }
                }
            }
            for(int k=0;k<m;k++)
            {
                if(k!=j1) f[i][k]=f[i-1][j1]+costs[i-1][k];
                else f[i][k]=f[i-1][j2]+costs[i-1][k];
            }
        }
            int res=INT_MAX;
            for(int i=0;i<m;i++)
            {
                res=min(res,f[n][i]);
            }
        return res;
    }
};

打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额

1 <= nums.length <= 100
0 <= nums[i] <= 400

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
题目

在这里插入图片描述

class Solution {
public:
    int rob(vector<int>& nums) {
        int n=nums.size();
        int f[110]={0};
        f[1]=nums[0];
        for(int i=2;i<=n;i++)
        {
            f[i]=max(f[i-1],f[i-2]+nums[i-1]);
        }
        return f[n];
    }
};

打家劫舍2

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

1 <= nums.length <= 100
0 <= nums[i] <= 1000

示例 1:

输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:

输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 3:

输入:nums = [0]
输出:0

分析:在上一题的基础上分成两种状态进行讨论 第1家房子是否取
当第1家取的时候 即转化成 1-n-1家的状态
当第一家不取的时候 即转化成2~n家的状态

class Solution {
public:
    int rob(vector<int>& nums) {
        int n=nums.size();
        if(n==1) return nums[0];
        if(n==2) return nums[0]>nums[1]?nums[0]:nums[1];
        int f[101]={0};
        //当第一家取的时候,进行讨论
        f[1]=nums[0];
        int Max1=0,Max2=0;
        for(int i=2;i<=n-1;i++)
        {
            f[i]=max(f[i-1],f[i-2]+nums[i-1]);
        }
        Max1=f[n-1];
        memset(f,0,sizeof f);
        f[2]=nums[1];
        for(int i=3;i<=n;i++)
        {
            f[i]=max(f[i-1],f[i-2]+nums[i-1]);
        }
        Max2=f[n];
        return Max1>Max2?Max1:Max2;
    }
};

买卖股票的最佳时间

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

1 <= prices.length <= 105
0 <= prices[i] <= 104

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

分析:根据涂黄色部分可以得到这只股票只能买卖一次
在这里插入图片描述

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size(),sum=0;
        int f[n+1];
        f[0]=0;
        int min1=prices[0];
        for(int i=1;i<=n;i++)
        {
            f[i]=max(f[i-1],prices[i-1]-min1);
            min1=min(prices[i-1],min1);//进行基表最小值
        }
        return f[n];
    }
};

买卖股票的最佳时间II

给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104

示例 1:

输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:

输入: prices = [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:

输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

由于可以买卖多次,可以借助贪心的思想,进行计算,只要前后两天有利润,就进行贪心买卖,当然也可以进行dp,贪心的证明可以借助股票图来进行证明

dp的转移方程: f[i]=max(f[i-1],f[i-1]+price[i-1]-price[i-2]);

class Solution {
public:
    int maxProfit(vector<int>& prices) {
         int n=prices.size(),sum=0;
        for(int i=0;i<n-1;i++)
        {
            if(prices[i]<prices[i+1])
            sum+=prices[i+1]-prices[i];
        }
        return sum;
    }
};

买卖股票的最佳时间III

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

1 <= prices.length <= 105
0 <= prices[i] <= 105

示例 1:

输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
示例 4:

输入:prices = [1]
输出:0

在这里插入图片描述

class Solution {
public:
    int Max(int x,int y,int z)
    {
        int t=max(x,y);
        return t>z?t:z;
    }
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        int f[100100][6]={0};
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=5;j+=2)//无票
            {
                f[i][j]=f[i-1][j];
                if(i>1&&j>1)
                f[i][j]=max(f[i][j],f[i-1][j-1]+prices[i-1]-prices[i-2]);//昨天有票
            }
            for(int j=2;j<6;j+=2)//有票
            {
                f[i][j]=f[i-1][j-1];//昨天无票
                if(i>1)//昨天有票
                f[i][j]=max(f[i][j],f[i-1][j]+prices[i-1]-prices[i-2]);
                //假设昨天处于阶段2时候进行讨论,今天卖出,今天又买入
                if(i>1&&j>2)
                f[i][j]=max(f[i][j],f[i-1][j-2]+prices[i-1]-prices[i-2]);
            }
        }
        return Max(f[n][1],f[n][3],f[n][5]);
    }
};

买卖股票的最佳时间IV

给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

0 <= k <= 100
0 <= prices.length <= 1000
0 <= prices[i] <= 1000

示例 1:

输入:k = 2, prices = [2,4,1]
输出:2
解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
示例 2:

输入:k = 2, prices = [3,2,6,5,0,3]
输出:7
解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。

可以与上一题类似

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n=prices.size();
        int f[100100][210]={0};
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=2*k+1;j+=2)//无票
            {
                f[i][j]=f[i-1][j];
                if(i>1&&j>1)
                f[i][j]=max(f[i][j],f[i-1][j-1]+prices[i-1]-prices[i-2]);//昨天有票
            }
            for(int j=2;j<=2*k+1;j+=2)//有票
            {
                f[i][j]=f[i-1][j-1];//昨天无票
                if(i>1)//昨天有票
                f[i][j]=max(f[i][j],f[i-1][j]+prices[i-1]-prices[i-2]);
                //假设昨天处于阶段2时候进行讨论,今天卖出,今天又买入
                if(i>1&&j>2)
                f[i][j]=max(f[i][j],f[i-1][j-2]+prices[i-1]-prices[i-2]);
            }
        }
        int res=0;
        for(int i=1;i<=2*k+1;i++)
        {
            res=max(res,f[n][i]);
        }
        return res;
    }
};
  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值