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. linux 进程通信之 共享内存

    共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...

  2. c/c++ 数据结构之位图(bitmap)具体解释

    1.  概述 位图(bitmap)是一种很经常使用的结构,在索引.数据压缩等方面有广泛应用. 本文介绍了位图的实现方法及其应用场景. 2. 位图实现 2014728101320" alt=& ...

  3. 一步步玩pcDuino3--mmc下的bootloader

    pcDuino3下支持mmc启动.官方的Uboot是採用SPL框架实现的,由于内部的SRAM空间达到32K,我们全然能够在这32K空间内编写一个完整可用小巧的bootloader来完毕引导Linux ...

  4. [NOIP 2014] 寻找道路

    [题目链接] http://uoj.ac/problem/19 [算法] 首先,在反向图上从终点广搜,求出每个点是否可以在答案路径中 然后在正向图中求出源点至终点的最短路,同样可以使用广搜 时间复杂度 ...

  5. heap堆&&priority_queue优先队列

    堆(heap)不是stl中的东西...它分为 max heap 和min heap. 但我不想用这些,而是采用了priority_queue,优先队列,定义在queue中.顾名思义,它的作用就是无论怎 ...

  6. Wireshark抓取RTP包,还原语音

    最近在做基于SIP的VoIP通信研究,使用Wireshark软件可以对网络流量进行抓包. VoIP使用RTP协议对语音数据进行传输,语音载荷都封装在RTP包里面.要对传输中的语音进行截获和还原,需要通 ...

  7. MySQL SQL优化教程

    转自:https://www.cnblogs.com/duanxz/archive/2013/02/01/2889413.html 一,查询SQL执行效率 通过show status命令了解各种SQL ...

  8. tp 推送微信的模板消息

    设置推送类: <?php /** * tpshop 微信支付插件 * ============================================================== ...

  9. POJ 1160 DP

    题目: poj 1160 题意: 给你n个村庄和它的坐标,现在要在其中一些村庄建m个邮局,想要村庄到最近的邮局距离之和最近. 分析: 这道题.很经典的dp dp[i][j]表示建第i个邮局,覆盖到第j ...

  10. SVN 报错 sqlite[S11]: database disk image is malformed

    svn 提示数据库损坏 SVN 报错 sqlite[S11]: database disk image is malformed 解决办法:网上说的打开wc.db删除lock表 不管用.我发现这样可以 ...