[LeetCode] 动态规划入门题目
最近接触了动态规划这个厉害的方法,还在慢慢地试着去了解这种思想,因此就在LeetCode上面找了几道比较简单的题目练了练手。
首先,动态规划是什么呢?很多人认为把它称作一种“算法”,其实我认为把它称作一种“思想”更为合适;利用动态规划去解决问题,其实就是逐步递推的过程,与贪心算法不同,动态规划递推的每一步都要求是当前的最优解(这是很重要的,递推的正确性依赖的就是这一点);利用动态规划解题时,必须自己定义出来状态和状态转移方程。然而,看上去简单,做起来却非常困难,因为解题时的具体形式千差万别,找出问题的子结构以及通过子结构重新构造最优解的过程很难统一。
经典的动态规划题目有背包问题、硬币问题等等,可以通过这些题目去理解一下这个东西。
我认为,动态规划最难的就是找出状态方程。同时,个人认为比较难理解的一点是,懂得“前面每一步都是最优解”这个前提。
废话不多说,直接看看LeetCode上简单的动态规划题目。
要注意的是,下面的三题都用到了局部最优和全局最优解法:
1.Jump Game
原题地址:https://leetcode.com/problems/jump-game/description/
解法:
用一个global变量保存到目前为止能跳的最远距离,用一个local变量保存当前一步出发能跳的最远距离,这题里面的状态就是走到每一步时的global[i]值,状态转移方程就是global[i] =max{nums[i] + i, global[i-1]}。当然,写代码的时候用变量代替数组即可。
class Solution {
public:
bool canJump(vector<int>& nums) {
int reach = ;
for (int i = ; i < nums.size() - && reach >= i; i++) {
reach = nums[i] + i > reach ? nums[i] + i : reach;
}
return reach >= nums.size() - ;
}
};
2.Maximum Subarray
原题地址:https://leetcode.com/problems/maximum-subarray/description/
解法:
这一题要维护两个变量:global和local,与上面一题一样,local保存包含当前元素的最大值(局部最优),global保存的是所有情况里面的最大值(全局最优)。假设第i步的local[i]和global[i]已知,那么第i+1步的local[i + 1] = max{ nums[i] + local[i], nums[i + 1] },global[i + 1] = max{global[i], local[i + 1]}。代码如下:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int global = nums[], local = nums[];
for (int i = ; i < nums.size(); i++) {
local = nums[i] > nums[i] + local ? nums[i] : nums[i] + local;
global = local > global ? local : global;
}
return global;
}
};
3.Best Time to Buy and Sell Stock
原题地址:https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/
这道题目有两种方法,其实都是动态规划:
(1)
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() == ) return ;
int maxPrice = prices[prices.size() - ];
int res = ;
for (int i = prices.size() - ; i >= ; i--) {
maxPrice = max(maxPrice, prices[i]);
res = max(res, maxPrice - prices[i]);
}
return res;
}
};
这种解法在这个博客里面讲得很详细:http://www.cnblogs.com/remlostime/archive/2012/11/06/2757434.html
(2)局部最优和全局最优解法:
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() == ) return ;
int local = , global = ;
for (int i = ; i < prices.size(); i++) {
local = max(, local + prices[i] - prices[i - ]);
global = max(local, global);
}
return global;
}
};
local = max(0, local + prices[i] - prices[i - 1])这一句,我一开始在考虑:为什么不写成local = max(local, local + prices[i] - prices[i - 1])呢?
后来想了一下,因为假如这样写,有可能得到的就不是包含当前元素的局部最优解了。所以,在“局部最优和全局最优解法”里面,永远不会出现local=local的情况。 4.Minimum Path Sum
原题地址:https://leetcode.com/problems/minimum-path-sum/description/
这道题目不需用到上面的“局部最优和全局最优”解法,只需要每次选出最优的即可。除了边界的元素,其他元素的最优都是 min{min[i - 1][j] + grid[i][j],min[i][j - 1] + grid[i][j]
}。
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int ** min = new int*[grid.size()];
for (int i = ; i < grid.size(); i++) {
min[i] = new int[grid[i].size()];
}
min[][] = grid[][];
for (int i = ; i < grid.size(); i++) {
for (int j = ; j < grid[i].size(); j++) {
if (i == && j == ) continue;
else if (i == ) min[i][j] = min[i][j - ] + grid[i][j];
else if (j == ) min[i][j] = min[i - ][j] + grid[i][j];
else min[i][j] = min[i - ][j] + grid[i][j] < min[i][j - ] + grid[i][j] ? min[i - ][j] + grid[i][j] : min[i][j - ] + grid[i][j] ;
}
}
return min[grid.size() - ][grid[grid.size() - ].size() - ];
return ;
}
};
5.Triangle
地址:https://leetcode.com/problems/triangle/description/
也是一道典型的dp题目,思想跟上面一题差不多:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
if (triangle.size() == ) return triangle[][];
int ** min = new int *[triangle.size()];
for (int i = ; i < triangle.size(); i++) {
min[i] = new int[triangle[i].size()];
}
min[][] = triangle[][];
int res = INT_MAX;
for (int i = ; i < triangle.size(); i++) {
for (int j = ; j < triangle[i].size(); j++) {
if (i == && j == ) continue;
else if (j == ) min[i][j] = min[i - ][j] + triangle[i][j];
else if (j == triangle[i].size() - ) min[i][j] = min[i - ][j - ] + triangle[i][j];
else min[i][j] = min[i - ][j - ] + triangle[i][j] < min[i - ][j] + triangle[i][j] ? min[i - ][j - ] + triangle[i][j] : min[i - ][j] + triangle[i][j];
if (min[i][j] < res && i == triangle.size() - ) {
res = min[i][j];
}
}
}
return res;
}
};
但这道题有趣的地方在于,空间复杂度可以缩小到O(n):我们把这个三角形倒过来看,便能发现可以通过复用一个一维数组来储存最小值:
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
vector<int> min = triangle[triangle.size() - ];
for (int i = triangle.size() - ; i >= ; i--) {
for (int j = ; j <= i; j++) {
min[j] = min[j] < min[j + ] ? min[j] + triangle[i][j] : min[j + ] + triangle[i][j];
}
}
return min[];
}
};
[LeetCode] 动态规划入门题目的更多相关文章
- 洛谷P1028 数的计算 题解 动态规划入门题
题目链接:https://www.luogu.com.cn/problem/P1028 题目描述 我们要求找出具有下列性质数的个数(包含输入的自然数 \(n\) ): 先输入一个自然数 \(n(n \ ...
- 快速上手leetcode动态规划题
快速上手leetcode动态规划题 我现在是初学的状态,在此来记录我的刷题过程,便于以后复习巩固. 我leetcode从动态规划开始刷,语言用的java. 一.了解动态规划 我上网查了一下动态规划,了 ...
- leetcode - 位运算题目汇总(下)
接上文leetcode - 位运算题目汇总(上),继续来切leetcode中Bit Manipulation下的题目. Bitwise AND of Numbers Range 给出一个范围,[m, ...
- leetcode top 100 题目汇总
首先表达我对leetcode网站的感谢,与高校的OJ系统相比,leetcode上面的题目更贴近工作的需要,而且支持的语言广泛.对于一些比较困难的题目,可以从讨论区中学习别人的思路,这一点很方便. 经过 ...
- poj 2186 强连通入门题目
每头牛的梦想就是成为牛群中最受欢迎的牛. 在一群N(1 <= N <= 10,000)母牛中, 你可以得到M(1 <= M <= 50,000)有序的形式对(A,B),告诉你母 ...
- Problem C: 动态规划基础题目之数字三角形
Problem C: 动态规划基础题目之数字三角形 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 208 Solved: 139[Submit][Sta ...
- 树形DP入门题目推荐以及解析
关于树形DP几道入门题目 今天恶补树形DP,感觉海星. 其实挺简单的. 介绍几道例题,我会的. 1.洛谷P1352 没有上司的舞会 我的一篇题解 我们可以考虑每一个节点都是有两种情况. 一个是被邀请: ...
- leetcode tree相关题目总结
leetcode tree相关题目小结 所使用的方法不外乎递归,DFS,BFS. 1. 题100 Same Tree Given two binary trees, write a function ...
- 草地排水 洛谷P2740 最大流 入门题目
草地排水 洛谷P2740 最大流入门题目 题意 在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一 ...
随机推荐
- Linux笔记(固定USB摄像头硬件端口,绑定前后置摄像头)
在Android的系统会有前置摄像头和后置摄像头的定义,摄像头分为SOC类型的摄像头和USB这一类的摄像头,接下要分析就是USB摄像头这一类 . 一般在android或者linux系统中分析一个模块, ...
- cocos2dx3.0导出自定义类到lua的方法详细步骤
我写了一个用3.0的工具导出类到lua,自动生成代码的方法. 以前要导出c++类到lua,就得手动维护pkg文件,那简直就是噩梦,3.0以后就会感觉生活很轻松了. 下面我就在说下具体做法.1.安装必要 ...
- Mina自定义协议简单实现
因公司需要做个电子秤自动称重系统,需要自定义协议实现,所以就用Mina简单实现了一下,有时间改成Netty版 服务端 package net.heartma.server;import java.io ...
- pyhton 关于 configparser 配置 模块 实践使用中碰到的坑
今天做一个ATM的练习,想要用configparser模块,写一个配置文件,存放用户信息. 结果状况连连,叫苦不迭. 我用configparser模块,想要对配置文件,进行读.写.改.查 功能. 其中 ...
- Django的ModelForm组件
创建类 from django.forms import ModelForm from django.forms import widgets as wd from app01 import mode ...
- [C#]使用Label标签控件模拟窗体标题的移动
本文为原创文章.源代码为原创代码,如转载/复制,请在网页/代码处明显位置标明原文名称.作者及网址,谢谢! 开发工具:VS2017 语言:C# DotNet版本:.Net FrameWork 4.0及以 ...
- 探究PHP底层
探究PHP底层 1.PHP是什么? PHP 指的是我们从外面看到的一套完整的系统.这听起来有点糊涂,但其实并不复杂(PHP4 内部结构图).从功能上来分:我们可以分为三部分: 1. 解释器部分(Z ...
- [设计模式]PHP设计模式之单例模式
面试最常见的问题之一就是 请问您知道哪些设计模式这次先介绍最经典的单例模式.单例模式分3种:懒汉式单例.饿汉式单例.登记式单例.单例模式有以下3个特点:1.只能有一个实例.2.必须自行创建这个实例. ...
- UWP 邮件反馈
在我们构建App的时候,一个很人性化的设计就是增加邮件反馈渠道,就是让用户直接发邮件给你反馈. 当然,你也可以用系统自带的"反馈中心"(超级无敌难用,还经常打不开),或者使用商店的 ...
- 使用vee-validate表单插件是如何设置中文提示?
最近在写vue表单验证的时候,在网上找到一款不错的插件vee-validate,在使用的过程中发现配置不了中文提示,这就很苦恼了,基本上网上的配置办法我都看过,都是有问题的,比如这种 import z ...