Leetcode 动态规划 - 简单
1. 最大子序和 (53)
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
解题思路-1:
当子数组和为负数时,对后面的元素来说,其没有增益(负数会让所有与其相加的元素的和变小),舍去。从下一个元素重新开始计算连续字数组的和。定义一个最终值的存储变量存储所有子序列的最大值。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int maxEnd = nums[],conSum=nums[]; for(int i=;i<nums.size();i++){
if(conSum<){
conSum=nums[i];
}else{
conSum+=nums[i];
}
maxEnd = (maxEnd<conSum?conSum:maxEnd);
}
return maxEnd;
}
};
解题思路-2:
根据题目关键词,“最大”“连续”,可以判断是一道动态规划。
1)定义一个函数f(n),以第n个数为结束点的子数列的最大和,存在一个递推关系f(n) = max(f(n-1) + A[n], A[n]);
2)将这些最大和保存下来后,取最大的那个就是,最大子数组和。因为最大连续子数组 等价于 最大的以n个数为结束点的子数列和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size() == ) return NULL;
int res = INT_MIN;
int f_n = -;
for(int i = ; i < nums.size(); ++i){
f_n = max(nums[i], f_n + nums[i]);
res = max(f_n, res);
}
return res;
}
};
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
2. 买卖股票的最佳时机 (121)
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
解题思路:
动态规划 前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格}
#include<iostream>
#include<string>
#include<map>
#include<bits/stdc++.h> using namespace std; class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size()<=)
return ;
int minV = prices[],maxV = prices[]-prices[]; //maxV = prices[0] 不能初始化位第一个值
for(int i=;i<prices.size();i++){
minV = min(minV,prices[i]);
maxV = max(maxV,prices[i]-minV);
}
return maxV;
}
}; int main(){
Solution obj;
int temp;
vector<int> prices;
while(cin>>temp){
prices.push_back(temp);
} cout<<obj.maxProfit( prices)<<endl;
}
注意:
编写程序的时候注意minV与maxV的初始取值。maxV = prices[0]是错误的,不能初始化为第一个值,应该初始化为插值
3. 打家劫舍 (198)
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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 。
解题思路:
动态规划:状态转移方程:
dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
对于这类求极值的问题首先考虑动态规划Dynamic Programming来解,我们维护一个一位数组dp,其中dp[i]表示到i位置时不相邻数能形成的最大和。
状态方程怎么求解:
比如:nums为{3, 2, 1, 5},首先dp[0]=3,由于3比2大,所以我们抢第一个房子的3,当前房子的2不抢,所以dp[1]=3。那么再来看dp[2],由于不能抢相邻的,所以我们可以用再前面的一个的dp值加上当前的房间值,和当前房间的前面一个dp值比较,取较大值当做当前dp值,所以我们可以得到状态转移方程dp[i] = max(num[i] + dp[i - 2], dp[i - 1]), 由此看出我们需要初始化dp[0]和dp[1],其中dp[0]即为num[0],dp[1]此时应该为max(num[0], num[1])。
代码
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size()<=)
return (nums.empty() ? : nums[]); //可以用num.empty() ?作为三元运算符的判断
//初始化前两个元素
vector<int> res = {nums[],max(nums[],nums[])};//可以只初始化前两个元素 for(int i=;i<nums.size();i++)
res.push_back(max(res[i-],res[i-]+nums[i]));
//注意前面res只初始化了两个元素,因此接下来的元素存储,应该用push_back而不是res[i],
//当前res[i]并不存在
return res.back(); }
};
4. 使用最小花费爬楼梯(746)
数组的每个索引做为一个阶梯,第 i
个阶梯对应着一个非负数的体力花费值 cost[i]
(索引从0开始)。
每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。
您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。
示例 1:
输入: cost = [10, 15, 20]
输出: 15
解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。
示例 2:
输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出: 6
解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。
注意:
cost
的长度将会在[2, 1000]
。- 每一个
cost[i]
将会是一个Integer类型,范围为[0, 999]
。
解题思路:
用dp[i]表示爬到第i层的最小花费
每爬上一个楼梯后你可以选择爬一级或两级楼梯,因此每次都是从前面一级或者是前面两级的位置过来的。
使用方程:dp[i] = min( dp[i-2], dp[i-1] ) + cost[i]; 则dp[0]=cost[0],dp[1]=cost[1];
//dp[i] = min(dp[i-1],dp[i-2])+cost[i];
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
if(n<=1)
return 0;
if(n==2)
return min(cost[0],cost[1]); //vector<int> dp(n) = {cost[0],cost[1]}; //error 不能这样初始化? vector<int> dp(n,0);
dp[0] = cost[0];
dp[1] = cost[1]; for(int i=2;i<n;i++){
dp[i] = min(dp[i-1],dp[i-2])+cost[i]; } return min(dp[n-2], dp[n-1]);
}
};
使用方程:dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
则dp[0]=0,dp[1]=0;
//dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
if(n<=1)
return 0;
if(n==2)
return min(cost[0],cost[1]); vector<int> dp(n+1,0); //需要n+1个数字去存储!!
for(int i=2;i<=n;i++){ //要有=n,否则是错误的!!
dp[i] = min(dp[i-2]+cost[i-2], dp[i-1]+cost[i-1]);
//dp[i]中存储的是i之前的最小代价,并没有计算i的代价,想获得i的代价,要求解i+1。
} return dp[n];
}
};
5. 区域和检索 - 数组不可变 (303)
给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。
示例:
给定 nums = [-2, 0, 3, -5, 2, -1],求和函数为 sumRange() sumRange(0, 2) -> 1
sumRange(2, 5) -> -1
sumRange(0, 5) -> -3
说明:
- 你可以假设数组不可变。
- 会多次调用 sumRange 方法。
解题思路:
dp[i]存储从0到i的子数组元素和,当求解从2-5,用dp[5]-dp[1]即可。
class NumArray {
public:
NumArray(vector<int>& nums) {
int n = nums.size();
if(n==0) //!!! 必须要有这个判断,否则会报错(执行错误)
return;
//vector<int> dp(n,0); 私有变量已经定义过了
dp.push_back(nums[0]);
for(int i=1;i<n;i++)
dp.push_back(dp[i-1]+nums[i]);
} int sumRange(int i, int j) {
if(i>j || i<0 ||j>=dp.size()) //异常值
return 0;
if(i==0)
return dp[j]; return dp[j]-dp[i-1];
}
private:
vector<int> dp;
}; /**
* Your NumArray object will be instantiated and called as such:
* NumArray* obj = new NumArray(nums);
* int param_1 = obj->sumRange(i,j);
*/
编写程序的时候注意:
1. 构造函数里,必须要判断nums是否为空,因为下面会访问nums[0]。为空直接返回。否则会报错。
2. 私有变量dp定义的时候没有定义元素的个数,因此添加元素要使用push_back();
Leetcode 动态规划 - 简单的更多相关文章
- [LeetCode] 动态规划入门题目
最近接触了动态规划这个厉害的方法,还在慢慢地试着去了解这种思想,因此就在LeetCode上面找了几道比较简单的题目练了练手. 首先,动态规划是什么呢?很多人认为把它称作一种"算法" ...
- 快速上手leetcode动态规划题
快速上手leetcode动态规划题 我现在是初学的状态,在此来记录我的刷题过程,便于以后复习巩固. 我leetcode从动态规划开始刷,语言用的java. 一.了解动态规划 我上网查了一下动态规划,了 ...
- Leetcode题目198.打家劫舍(动态规划-简单)
题目描述: 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给 ...
- Leetcode题目53.最大子序和(动态规划-简单)
题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4],输出: 6解释: 连 ...
- LeetCode - 198 简单动态规划 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个代表每 ...
- LeetCode动态规划题总结【持续更新】
以下题号均为LeetCode题号,便于查看原题. 10. Regular Expression Matching 题意:实现字符串的正则匹配,包含'.' 和 '*'.'.' 匹配任意一个字符,&quo ...
- leetcode动态规划题目总结
Hello everyone, I am a Chinese noob programmer. I have practiced questions on leetcode.com for 2 yea ...
- LeetCode 动态规划
动态规划:适用于子问题不是独立的情况,也就是各子问题包含子子问题,若用分治算法,则会做很多不必要的工作,重复的求解子问题,动态规划对每个子子问题,只求解一次将其结果保存在一张表中,从而避免重复计算. ...
- LeetCode~报数(简单)
报数(简单) 题目描述: 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数.其前五项如下: 1 11 21 1211 111221 1 被读作 "one 1" ( ...
随机推荐
- JEval使用实例
jeval是为为你的Java应用程序提供可增加的.高性能.数学. 布尔和函数表达式的解析和运算的高级资源包. 以下这个样例包括了JEval经常使用功能: package demo0; import ...
- Supervisor-进程监控自动重启
Supervisor是一个进程监控程序. 需求一:我现在有一个进程需要每时每刻不断的跑,但是这个进程又有可能由于各种原因有可能中断.当进程中断的时候我希望能自动重新启动它,此时,我就需要使用到了Sup ...
- Android之怎样使用ListView列表视图
ListView 列表视图创建方法: (1)直接使用ListView 组件创建 (2)让Activity继承ListActivity实现 第一种:在XML中直接使用ListView 组件创建 在val ...
- 解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”
解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合” 最近更新: 2013-2-15 587 很少写WinForm程序第一次使用ListBox控件就遇到了比 ...
- CodeForces - 749C Voting
C. Voting time limit per test 1 second memory limit per test 256 megabytes input standard input outp ...
- 杂项:Web API
ylbtech-杂项:Web API 今天的web计算平台包含了广泛的功能,其中的大部分均可以通过API(应用程序编程接口)访问. 从简单的社会书签服务del.icio.us,到复杂得多的amazon ...
- PCB MS SQL 行转列(动态拼SQL)
一.原数据: SELECT inman,indate FROM [fp_db].[dbo].[ppezhpbb] WHERE indate > '2016-5-1' AND indate < ...
- 0604-面向对象、类与对象、类、static、构造方法/析构方法
一.面向对象 1.面向过程:一个人分步骤完成某个事情 2.面向对象:某件事情拆分为多个任务,由每个对象独立完成,最后调用整合为一个完整的项目 3.三要素:继承.封装.多态. 封装:私有化属性 提供公共 ...
- [BZOJ1041]圆上的整点
嗯... 自己看视频讲解? >Click Here< #include<cstdio> #include<queue> #include<iostream&g ...
- mvp 不错的链接
http://www.imooc.com/wenda/detail/216700 http://www.cnblogs.com/mybkn/archive/2012/04/12/2443676.htm ...