文章标题借用了Hawstein的译文《动态规划:从新手到专家》。

1. 概述

动态规划( Dynamic Programming, DP)是最优化问题的一种解决方法,本质上状态空间的状态转移。所谓状态转移是指每个阶段的最优状态(对应于子问题的解)可以从之前的某一个或几个阶段的状态中得到,这个性质叫做最优子结构。而不管之前这个状态是如何得到的,这被称之为无后效性

DP问题中最经典的莫过于01背包问题:

有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值;则其状态转移方程:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

2. 题解

LeetCode题目 归类
53. Maximum Subarray 子数组最大和
121. Best Time to Buy and Sell Stock 子数组最大和
122. Best Time to Buy and Sell Stock II 子序列最大和
123. Best Time to Buy and Sell Stock III
188. Best Time to Buy and Sell Stock IV
55. Jump Game
70. Climbing Stairs
62. Unique Paths
63. Unique Paths II
64. Minimum Path Sum 最短路径
91. Decode Ways

以下代码既有Java,也有Go。

53. Maximum Subarray

子数组最大和问题,求解方法可用Kadane算法

121. Best Time to Buy and Sell Stock

题目大意:给定数组\(a[..]\),求解\(\max a[j] - a[i] \quad j > i\)。

解决思路:将数组a的相邻值相减(右边减左边)变换成数组b,上述问题转变成了求数组b的子数组最大和问题.

// Kadane algorithm to solve Maximum subArray problem
public int maxProfit(int[] prices) {
int maxEndingHere = 0, maxSoFar = 0;
for (int i = 1; i < prices.length; i++) {
maxEndingHere += prices[i] - prices[i - 1];
maxEndingHere = Math.max(maxEndingHere, 0);
maxSoFar = Math.max(maxEndingHere, maxSoFar);
}
return maxSoFar;
}

122. Best Time to Buy and Sell Stock II

之前问题Best Time to Buy and Sell Stock的升级版,对交易次数没有限制,相当于求解相邻相减后形成的子序列最大和——只要为正数,则应计算在子序列内。

public int maxProfit(int[] prices) {
int max = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
max += (prices[i] - prices[i - 1]);
}
}
return max;
}

123. Best Time to Buy and Sell Stock III

最多允许交易两次。

public int maxProfit(int[] prices) {
int sell1 = 0, sell2 = 0;
int buy1 = Integer.MIN_VALUE, buy2 = Integer.MIN_VALUE;
for (int price : prices) {
buy1 = Math.max(buy1, -price); // borrow
sell1 = Math.max(sell1, buy1 + price);
buy2 = Math.max(buy2, sell1 - price);
sell2 = Math.max(sell2, buy2 + price);
}
return sell2;
}

188. Best Time to Buy and Sell Stock IV

最多允许交易k次。当k >= n/2时,在任意时刻都可以进行交易(一次交易包括买、卖),因此该问题退化为了问题122. Best Time to Buy and Sell Stock II。其他情况则有递推式:

\[c_{i,j} = \max (c_{i,j-1}, \ \max (c_{i-1,t} - p_t) + p_j),\quad 0 \leq t < j
\]

其中,\(c_{i,j}\)表示在\(t\)时刻共\(i\)次交易产生的最大收益。

public int maxProfit(int k, int[] prices) {
int n = prices.length;
if (n <= 1) {
return 0;
}
// make transaction at any time
else if (k >= n / 2) {
return maxProfit122(prices);
}
int[][] c = new int[k + 1][n];
for (int i = 1; i <= k; i++) {
int localMax = -prices[0];
for (int j = 1; j < n; j++) {
c[i][j] = Math.max(c[i][j - 1], localMax + prices[j]);
localMax = Math.max(localMax, c[i - 1][j] - prices[j]);
}
}
return c[k][n - 1];
} public int maxProfit122(int[] prices) {
int max = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
max += (prices[i] - prices[i - 1]);
}
}
return max;
}

55. Jump Game

限制当前最大跳跃数,问是否能到达最后一个index。需要反向往后推演。

public boolean canJump(int[] nums) {
int n = nums.length, index = n - 1;
for (int i = n - 2; i >= 0; i--) {
if (i + nums[i] >= index)
index = i;
}
return index <= 0;
}

70. Climbing Stairs

题目大意:每一次可以加1或加2,那么从0加到n共有几种加法?

假定\(d_i\)表示加到i的种数,那么就有递推式\(d_i = d_{i-1} + d_{i-2}\)。

func climbStairs(n int) int {
if(n < 1) {
return 0;
}
d := make([]int, n+1)
d[1] = 1
if n >= 2 {
d[2] = 2
}
for i := 3; i<=n; i++ {
d[i] = d[i-1] + d[i-2]
}
return d[n]
}

62. Unique Paths

题目大意:求解从左上角到右下角的路径数。

路径数递推式:\(c_{i,j}= c_{i-1,j} + c_{i,j-1}\)。

func uniquePaths(m int, n int) int {
f := make([][]int, m)
for i := range f {
f[i] = make([]int, n)
}
// handle boundary condition: f[][0] and f[0][]
f[0][0] = 1
for i := 1; i < m; i++ {
f[i][0] = 1
}
for j := 1; j < n; j++ {
f[0][j] = 1
}
for i := 1; i < m; i++ {
for j := 1; j < n; j++ {
f[i][j] = f[i][j - 1] + f[i - 1][j]
}
}
return f[m-1][n-1]
}

63. Unique Paths II

加了限制条件,有的点为obstacle——不允许通过。上面的递推式依然成立,只不过要加判断条件。另外,在实现过程中可以用一维数组代替二维数组,比如说按行或按列计算。

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int columnSize = obstacleGrid[0].length;
int[] c = new int[columnSize];
c[0] = 1;
for (int[] row : obstacleGrid) {
for (int j = 0; j < columnSize; j++) {
if (row[j] == 1)
c[j] = 0;
else if (j >= 1)
c[j] += c[j - 1];
}
}
return c[columnSize - 1];
}

64. Minimum Path Sum

题目大意:从矩阵的左上角到右下角的最短路径。

加权路径值\(c_{i,j}= \max (c_{i-1,j},c_{i,j-1}) + w_{i,j}\),其中,\(w_{i,j}\)为图中边的权值。

// the shortest path for complete directed graph
func minPathSum(grid [][]int) int {
var m, n = len(grid), len(grid[0])
f := make([][]int, m)
for i := range f {
f[i] = make([]int, n)
}
// handle boundary condition: f[][0] and f[0][]
f[0][0] = grid[0][0]
for i := 1; i < m; i++ {
f[i][0] = f[i - 1][0] + grid[i][0]
}
for j := 1; j < n; j++ {
f[0][j] = f[0][j-1] + grid[0][j]
}
for i :=1; i < m; i++ {
for j := 1; j<n; j++ {
if(f[i-1][j] < f[i][j-1]) {
f[i][j] = f[i-1][j] + grid[i][j]
} else {
f[i][j] = f[i][j-1] + grid[i][j]
} }
}
return f[m-1][n-1]
}

91. Decode Ways

求解共有多少种解码情况。

public int numDecodings(String s) {
int n = s.length();
if (n == 0 || (n == 1 && s.charAt(0) == '0'))
return 0;
int[] d = new int[n+1];
d[n] = 1;
d[n - 1] = s.charAt(n - 1) == '0' ? 0 : 1;
for (int i = n-2; i >= 0; i--) {
if(s.charAt(i) == '0')
continue;
else if(Integer.parseInt(s.substring(i, i+2)) <= 26)
d[i] += d[i + 2];
d[i] += d[i + 1];
}
return d[0];
}

【LeetCode题解】动态规划:从新手到专家(一)的更多相关文章

  1. [LeetCode 题解]:Best Time to Buy and Sell Stock

    前言   [LeetCode 题解]系列传送门:  http://www.cnblogs.com/double-win/category/573499.html   1.题目描述 Say you ha ...

  2. Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner)

    Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner) 给定一个表示分数的非负整数数组. 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端 ...

  3. Leetcode之动态规划(DP)专题-877. 石子游戏(Stone Game)

    Leetcode之动态规划(DP)专题-877. 石子游戏(Stone Game) 亚历克斯和李用几堆石子在做游戏.偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] . 游戏以谁手中的石子最 ...

  4. LeetCode题解分类汇总(包括剑指Offer和程序员面试金典,持续更新)

    LeetCode题解汇总(持续更新,并将逐步迁移到本博客列表中) 剑指Offer 数据结构 链表 序号 题目 难度 06 从尾到头打印链表 简单 18 删除链表的节点 简单 22 链表中倒数第k个节点 ...

  5. 【LeetCode题解】二叉树的遍历

    我准备开始一个新系列[LeetCode题解],用来记录刷LeetCode题,顺便复习一下数据结构与算法. 1. 二叉树 二叉树(binary tree)是一种极为普遍的数据结构,树的每一个节点最多只有 ...

  6. LeetCode之“动态规划”:Distinct Subsequences

    题目链接 题目要求: Given a string S and a string T, count the number of distinct subsequences of T in S. A s ...

  7. leetcode题解-122买卖股票的最佳时期

    题目 leetcode题解-122.买卖股票的最佳时机:https://www.yanbinghu.com/2019/03/14/30893.html 题目详情 给定一个数组,它的第 i 个元素是一支 ...

  8. 【LeetCode题解】3_无重复字符的最长子串(Longest-Substring-Without-Repeating-Characters)

    目录 描述 解法一:暴力枚举法(Time Limit Exceeded) 思路 Java 实现 Python 实现 复杂度分析 解法二:滑动窗口(双指针) 思路 Java 实现 Python 实现 复 ...

  9. 【LeetCode题解】225_用队列实现栈(Implement-Stack-using-Queues)

    目录 描述 解法一:双队列,入快出慢 思路 入栈(push) 出栈(pop) 查看栈顶元素(peek) 是否为空(empty) Java 实现 Python 实现 解法二:双队列,入慢出快 思路 入栈 ...

随机推荐

  1. Linux_Ununtu 16.04 的下载安装并部署.Net Core 网站

    第一次接触Linux也难免有些懵逼,因为公司项目必须用.Net Core 开发一个后端服务应用:第一次用Linux给我的感觉就像在用2000年的手机一样:没用智能的操作:让人崩溃的用户体验.说多了都是 ...

  2. 将数据库从服务器移到浏览器--indexedDB基本操作封装

    数据库是属于服务器的,这是天经地义的事,但是有时候数据也许并非需要存储在服务器,但是这些数据也是一条一条的记录,怎么办?今天来带领你领略一下H5的一个新特性--indexedDB的风骚.你会情不自禁的 ...

  3. thinkphp5.0学习笔记(四)数据库的操作

    ThinkPHP内置了抽象数据库访问层,把不同的数据库操作封装起来,我们只需要使用公共的Db类进行操作,而无需针对不同的数据库写不同的代码和底层实现,Db类会自动调用相应的数据库驱动来处理.采用PDO ...

  4. 【DG】[三思笔记]一步一步学DataGuard

    [DG][三思笔记]一步一步学DataGuard 它有无数个名字,有人叫它dg,有人叫它数据卫士,有人叫它data guard,在oracle的各项特性中它有着举足轻理的地位,它就是(掌声)..... ...

  5. ASP.NET Core部署到CentOS7,使用Nginx代理

    ASP.NET Core 的运行环境由新开发的 Kestrel Server 负责,IIS 退回到 HTTP 的侦听器的角色,微软也特别为了这个需求开发了 IIS Platform Handler,以 ...

  6. 怀念Galois

    我的第一篇谈到具体学科的博客,还是献给我最钟爱的数学. 个人比较喜欢离散数学,并非因为曲高和寡,而是因为数学分析.概率论.拓扑学.泛函之类的高手实在太多.而离散数学更为抽象,抽象到抽象代数直接以抽象二 ...

  7. jeecg关闭当前iframe

    关闭当前iframe function closeDialog(){ frameElement.api.close();//本方法也行 //或者下面的方式 var win = frameElement ...

  8. java高并发锁的3种实现

    初级技巧 - 乐观锁 乐观锁适合这样的场景:读不会冲突,写会冲突.同时读的频率远大于写. 以下面的代码为例,悲观锁的实现: Java代码   public Object get(Object key) ...

  9. mysql 修改表结构的字段名

    alter table domains  change STATUS  status  tinyint(1)  not null;

  10. [leetcode-312-Burst Balloons]

    Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by ...