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. C++对象模型——对象复制语意学 (Object Copy Semantics)(第五章)

    5.3    对象复制语意学 (Object Copy Semantics) 当设计一个 class,并以一个 class object指定给 class object时,有三种选择:     1.什 ...

  2. 写一个android内置android程序

    当我们编译完毕android源代码之后,就须要对他做点什么事情,我如今正在看老罗的"Android源代码情景分析"一书.在这里主要是记录一些书中没有说清楚的地方. 相同.我们创建一 ...

  3. 阻尼滑动--能够滑动过度的ScrollView(OverScrollView)

    贴上一个我自己用过的阻尼滑动的ScrollView,像QQ里面那种滑动效果,尽管不是我写的,可是我认为还能够,贴出来做个记录,实用到的时候免得到处去找. 代码例如以下: /* * Copyright ...

  4. Openstack能解决这些问题吗?请各位大侠一起来讨论

    1.10万规模的虚拟机,每一个虚拟机能够在不论什么一个计算节点上启动,该怎样做?计算,存储,网络都是怎么拉通与配合的? 2.用户怎样自己定义业务网络,怎样解决网络不够用的情况?正常就4096个vlan ...

  5. C++顺序表(模板总结)

    C++顺序表(模板总结) 总结: 1.模板类的实质是什么:让程序员写出和类型无关的代码 2.模板的对象时什么:方法或者类 3.是对类中的一系列操作,提供一个不固定数据类型的方法 用模板做的类的时候要指 ...

  6. 清橙A1206.小Z的袜子 && CF 86D(莫队两题)

    清橙A1206.小Z的袜子 && CF 86D(莫队两题) 在网上看了一些别人写的关于莫队算法的介绍,我认为,莫队与其说是一种算法,不如说是一种思想,他通过先分块再排序来优化离线查询问 ...

  7. 从map到hash

    https://zybuluo.com/ysner/note/1175387 前言 这两种技巧常用于记录和去重量少而分散的状态. 都体现了映射思想. \(map\) 我一般是数组开不下时拿这玩意判重. ...

  8. java-com-util-common-service:BaseService.java

    ylbtech-java-com-util-common-service:BaseService.java 1.返回顶部 1. package com.shineyoo.manager.util.co ...

  9. PCB C# 连接MongoDB 数据库

    一.C# MongoDB 驱动下载 1.百度网盘:nuget下载地址(V2.7版本) https://pan.baidu.com/s/1VDsVcH1TMrXqhRCZVewZgA 2.VS 中NUg ...

  10. PCB Genesis加二维码 实现方式

    使用incam可以很轻松的增加2维码,这里通过另外一种方式玩转二维码的加法, 使用谷歌zxing.dll类库实现,将文字信息转为bitmap点阵后,在Genesis绘制点即可. 一.incam增加二维 ...