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。

注意:  

  1. cost 的长度将会在 [2, 1000]
  2. 每一个 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,求出数组从索引 到 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

说明:

  1. 你可以假设数组不可变。
  2. 会多次调用 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 动态规划 - 简单的更多相关文章

  1. [LeetCode] 动态规划入门题目

    最近接触了动态规划这个厉害的方法,还在慢慢地试着去了解这种思想,因此就在LeetCode上面找了几道比较简单的题目练了练手. 首先,动态规划是什么呢?很多人认为把它称作一种"算法" ...

  2. 快速上手leetcode动态规划题

    快速上手leetcode动态规划题 我现在是初学的状态,在此来记录我的刷题过程,便于以后复习巩固. 我leetcode从动态规划开始刷,语言用的java. 一.了解动态规划 我上网查了一下动态规划,了 ...

  3. Leetcode题目198.打家劫舍(动态规划-简单)

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

  4. Leetcode题目53.最大子序和(动态规划-简单)

    题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4],输出: 6解释: 连 ...

  5. LeetCode - 198 简单动态规划 打家劫舍

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

  6. LeetCode动态规划题总结【持续更新】

    以下题号均为LeetCode题号,便于查看原题. 10. Regular Expression Matching 题意:实现字符串的正则匹配,包含'.' 和 '*'.'.' 匹配任意一个字符,&quo ...

  7. leetcode动态规划题目总结

    Hello everyone, I am a Chinese noob programmer. I have practiced questions on leetcode.com for 2 yea ...

  8. LeetCode 动态规划

    动态规划:适用于子问题不是独立的情况,也就是各子问题包含子子问题,若用分治算法,则会做很多不必要的工作,重复的求解子问题,动态规划对每个子子问题,只求解一次将其结果保存在一张表中,从而避免重复计算. ...

  9. LeetCode~报数(简单)

    报数(简单) 题目描述: 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数.其前五项如下: 1 11 21 1211 111221 1 被读作 "one 1" ( ...

随机推荐

  1. java Regex

    超全 http://www.rexegg.com/regex-lookarounds.html 这篇文章不错:http://www.cnblogs.com/lzq198754/p/5780340.ht ...

  2. windows脚本(VBS)之cmd命令行的妙用

    windows脚本(VBS)之cmd命令行的妙用 (2009-08-06 13:40:55) 转载▼ 标签: 脚本 cmd 命令行 vbs js 简单 公式 windows it 分类: 计算机 脚本 ...

  3. Android之自己定义(上方标题随ViewPager手势慢慢滑动)

    近期非常蛋疼,项目要模仿网易新闻的样式去做.上次把仿网易新闻client的下拉刷新写出来了.这次是ViewPager的滑动,同一时候ViewPager的上面标题下划线尾随者移动.本来通过ViewPag ...

  4. Catalan数(卡特兰数)

    Catalan数(卡特兰数) 卡特兰数:规定h(0)=1,而h(1)=1,h(2)=2,h(3)=5,h(4)=14,h(5)=42,h(6)=132,h(7)=429,h(8)=1430,h(9)= ...

  5. codeforces 916E Jamie and Tree dfs序列化+线段树+LCA

    E. Jamie and Tree time limit per test 2.5 seconds memory limit per test 256 megabytes input standard ...

  6. [JSOI2016]独特的树叶

    https://zybuluo.com/ysner/note/1177340 题面 有一颗大小为\(n\)的树\(A\),现加上一个节点并打乱编号,形成树\(B\),询问加上的节点最后编号是多少? \ ...

  7. iOS获取相册/相机图片-------自定义获取图片小控件

    一.功能简介 1.封装了一个按钮,点击按钮,会提示从何处获取图片:如果设备支持相机,可以从相机获取,同时还可以从手机相册获取图片. 2.选择图片后,有一个block回调,根据需求,将获得的图片拿来使用 ...

  8. python关于文件的操作

    总是记不住API.昨晚写的时候用到了这些,但是没记住,于是就索性整理一下吧: python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Pyth ...

  9. nodejs--Nodejs单元测试小结

    前言 最近在写一课程的Project,用Node写了一个实时聊天小应用,其中就用到了单元测试.在写Node单元测试的时候,一方面感受到了单元测试的重要性,另一方面感受到了Node单元测试的不够成熟,尚 ...

  10. java jdk 管理工具

    官网:http://www.jenv.be/ 安装: Linux / OS X $ git clone https://github.com/gcuisinier/jenv.git ~/.jenv M ...