leetcode(动态规划专题)

线性DP

53. 最大子数组和

思路

题解:使用DP算法
把n^2个区间分为n类,对每一类进行max处理,然后再对各个类进行max处理最后得到答案.
1.其中f[i]表示在nums中以nums[i]为结尾的最大子序和。
2.根据分析可以列出状态转移方程 f[i] = max( nums[i] , f[i - 1] + nums[i] )
即当前的max状态,要么nums[i]自身,要么是f[i - 1] + nums[i] 这两种状态,二选一得出
最后的结果 ;可以优化为 int now = max(last, 0) + nums[i]; last表示上一次的f[i]状态值
,即f[i - 1]结尾的最大子序列和

code 

int maxSubArray(vector<int>& nums) {
	//res:最后所有状态的最终Max结果
	//lat:当前f[i]状态的Max
	int res = INT_MIN, last = 0;
	for (int i = 0; i < nums.size(); i++)
	{
		//当前f[i]状态最大值(使用下面的状态转移方程得出)
        //f[i] = max( nums[i] , f[i - 1] + nums[i] )
		int now = max(last, 0) + nums[i];
		/*
		最终是所有状态取一个max所以此处保存前后两个状态
		相互比较的最终结果
		*/
		res = max(now, res);
		//更新最后,当为i时候,f[i]的最大值,即last
		last = now;
	}
	return res;

}

优化后的代码

    int maxSubArray(vector<int>& nums) {
        int res = INT_MIN;
        for (int i = 0, last = 0; i < nums.size(); i ++ ) {
            last = nums[i] + max(last, 0);
            res = max(res, last);
        }
        return res;
    }

120. 三角形最小路径和

思路

code

//自上而下
int minimumTotal(vector<vector<int>>& nums) {
	int n = nums.size();
	vector<vector<long long>>f(n, vector<long long>(n));
	f[0][0] = nums[0][0];
	for(int i = 1; i < n ;i++)
		for (int j = 0; j <= i; j++)
		{
			f[i][j] = INT_MAX;
			//边界判断
			if (j > 0) f[i][j] = min(f[i][j], f[i - 1][j - 1] + nums[i][j]);
			if (j < i) f[i][j] = min(f[i][j], f[i - 1][j] + nums[i][j]);
		}
	long long res = INT_MAX;

	for (int i = 0; i < n; i++) res = min(res, f[n - 1][i]);
	return res;

}

//自下而上不需要考虑边界问题
int minimumTotal(vector<vector<int>>& f) {
   // f.size()-2 是因为最后一行不需要计算
	for (int i = f.size() - 2; i >= 0; i--)
		for (int j = 0; j <= i; j++)
			f[i][j] += min(f[i + 1][j], f[i + 1][j + 1]);
	return f[0][0];
}

63. 不同路径 II

思路

code

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& o) {
        int n = o.size();
        if (!n) return 0;
        int m = o[0].size();

        vector<vector<int>> f(n, vector<int>(m));
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                //判断如果不为障碍物的话才执行
                if (!o[i][j]) {
                    if (!i && !j) f[i][j] = 1;//特判左上角开始位置
                    else {
                        //如果不是第一行
                        if (i) f[i][j] += f[i - 1][j];
                        //如果不是第一列
                        if (j) f[i][j] += f[i][j - 1];
                    }
                }

        return f[n - 1][m - 1];

    }
};

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

121. 买卖股票的最佳时机

思路

此题目为一个动态规划的过程,目标是需要求得最大的利润。

1.最大利润(分析)把整个区间划分为若干份,计算出区间每一个的局部最大值,然后再比较出整体区间的最大值即为答案。

max(max[0],max[1],max[2],max[---])

2.当前最利润为:当前的元素prices[i] -  过往区间最小的值(minp),并且更新过往最大利润res

3.最终更新最小值(minp) = min(当前最小值(即prices[i]自身),过往区间最小值(minp)) 

4.总结 :线性记录 res 和 minp 始终为过往区间的(最大利润) 与 (最小值)

code

int maxProfit(vector<int>& prices) {
	//res为当前最终结果
	int res = 0;
	for (int i = 0, minp = INT_MAX; i < prices.size(); i++) {
	    //prices[i] - minp为当天最大利润
		//max(res, prices[i] - minp)为截止至今日,最大利润
		//res = max(res, prices[i] - minp);更新当前扫描的最大利润
		res = max(res, prices[i] - minp);
		//更新前面最小值(当前更新位置始终为整个区间的最小值)
		minp = min(minp, prices[i]);
	}
	return res;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

༄yi笑奈何

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值