本次文档也是对动态规划的 再认识 。
之前写过一些文章,在处理动态规划问题的时候依据的思路是 :暴力搜索->加缓存->动态规划。相关文章有:算法八——动态规划,动态规划——0-1背包问题,动态规划——矩阵中的最短路径长度等等。
最近在看问题的时候发现,只要能明白暴力搜索是怎么搜索的,跟哪些条件有关系,不经过前面2个步骤也能写出动态规划方程。大家知道动态规划方程出来了,基本上问题就解决了。写下文章记录一下 。
如果看不出和哪些条件有关系,或者找不到动态转换关系,还是要依据步骤一步一步来。
1 53. Maximum Subarray
输入:int数组,有正有负
输出:找到所有子数组的和,返回其中最大的。
规则:子数组是一个连续的数组,至少包含一个元素。
例如:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
分析:对于任意一个元素nums[i],可以开启一个子序列{nums[i]},也可以追加在前一个数字子序列的后面{…nums[i-1],nums[i]}。
对于开启一个子序列的情况 ,子数组和=nums[i]。
对于追加的情况:目标是要求子数组和,所以只要之前以nums[i-1]为结尾的子数组的和+nums[i]即可。假设dp[i]=以nums[i]为结尾的子数组的最大的和。
最后结果在所有dp元素中查找最大值。
dp[i] = Math.max(nums[i],nums[i+dp[i-1]])
动归特征:与前一个元素相关;与以前一个元素为结尾的子数组最大和相关。
之后就是写代码了。
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
int max = dp[0];
for(int i=1;i<n;i++){
dp[i] = Math.max(nums[i],dp[i-1]+nums[i]);
max = Math.max(max,dp[i]);
}
return max;
}
}
进一步空间优化,可以自己思考。
2 121. Best Time to Buy and Sell Stock
输入:int数组,表示每天的股价。
输出:最大的盈利
规则:只可以买一次,卖一次。只能先买后卖。
例子:
Input: [7,1,5,3,6,4]
Output: 5
Explanation: 在价格为1的时候买入,在价格为6的时候卖出。
分析:只能买卖一次,先买后卖,说明是要找
m
a
x
(
p
r
i
c
e
[
j
]
−
p
r
i
c
e
[
i
]
)
,
j
>
i
max(price[j]-price[i]),j>i
max(price[j]−price[i]),j>i。对于每一个j,只要找到
m
i
n
(
p
r
i
c
e
[
i
]
)
,
i
=
0
,
1...
j
−
1
min(price[i]),i=0,1...j-1
min(price[i]),i=0,1...j−1即可。
class Solution {
public int maxProfit(int[] prices) {
int maxProfit = 0;
int minPrice = Integer.MAX_VALUE;
for(int i=0;i<prices.length;i++){
minPrice = Math.min(minPrice,prices[i]);
maxProfit = Math.max(maxProfit,prices[i]-minPrice);
}
return maxProfit;
}
}