LeetCode初级算法——动态规划类——算法总结
PS:算法并非原创,总结的本意在于温故知新、巩固知识。侵删。
1、爬楼梯
使用JAVA解答,代码如下:
class Solution {
public int climbStairs(int n) {
if(n==1)return 1;
int sum[]=new int[n+1];
sum[0]=0;sum[1]=1;sum[2]=2;
for(int i=3;i<=n;i++){
sum[i]=sum[i-2]+sum[i-1];
}
return sum[n];
}
}
算法解析:
对于n层台阶,一开始可以选择爬1步或者爬2步。选择爬1步的话,对应的后续阶梯为n-1步,爬楼方法为sum[n-1]。对于爬2步,对应的后续阶梯为n-2步,爬楼方法为sum[n-2]。所以sum[n] = sum[n-1]+sum[n-2]。通过已知的1级、2级台阶的爬楼方法数,可以知道后续的数组元素值。
算法占用时空间资源:
2、买卖股票的最佳时机
使用JAVA解答,代码如下:
class Solution {
public int maxProfit(int[] prices) {
//解法二:动态规划法:用dp[i]表示第i天卖出的收益,则dp[i]=max(price[i]-min,maxProfit)
//时间复杂度:O(n),空间复杂度:O(1)
if(prices==null || prices.length==0)
return 0;
int len=prices.length;
int maxprofit=0,min=Integer.MAX_VALUE;
for(int i=0;i<len;i++){
if(prices[i]<min) //维护一个最小值
min=prices[i];
else if(prices[i]-min>maxprofit)
maxprofit=prices[i]-min;
}
return maxprofit;
}
}
算法解析:
这个问题,乍看和数组类中“买卖股票的最佳时机II”很相似,但是本题中规定只能买卖一次,所以需要进行最大收益的比较。
我们用dp[i]表示从第1天到第i天进行一笔交易能获得的最大收益,用min表示买入的最低价格,则dp[i]=max(price[i]-min,maxProfit),其中maxProfit是指已经找到的最大收益。由于只允许一次交易,所以要想获得最大收益,必须在价格最低的时候买入,最高的时候卖出,但是由于必须先买后卖,
也就是使用min表示最低买入,maxprofit表示最大收益。min最终会指向峰谷,而maxprofit一定是先谷后峰的最大差异值。
算法占用时空间资源:
3、最大子序和
使用JAVA解答,代码如下:
class Solution {
public int maxSubArray(int[] nums) {// 动态规划法
int sum=nums[0];
int n=nums[0];
for(int i=1;i<nums.length;i++) {
if(n>0)
n+=nums[i];
else
n=nums[i];
if(sum<n)
sum=n;
}
return sum;
}
}
算法解析:
sum表示整体的最大子数组之和。n存储当前的可能最大值,保留着之前遍历过的最大值的结果。当遍历结果仍然为正数时,n不断计算累计和,通过比较sun和n的大小观察最终的最大子数组之和;当遍历结果已经为负数时,由于在之前的遍历中,sum已经存入最大子数组之和,所以n可以重新赋值,开始新一轮的累加。
(原博文)每次运算只需要前一次的结果,因此并不需要像普通的动态规划那样保留之前所有的计算结果,只需要保留上一次的即可,因此算法的时间和空间复杂度都很小
算法占用时空间资源:
4、打家劫舍
使用JAVA解答,代码如下:
class Solution {
public int rob(int[] nums) {
if (nums.length == 0){
return 0;
}
if (nums.length == 1){
return nums[0];
}
if (nums.length == 2){
return Math.max(nums[0], nums[1]);
}
int[] result = new int[nums.length];
result[0] = nums[0];//只有一家的情况下,只能抢这一家了
result[1] = Math.max(nums[0], nums[1]);//有两家可选的情况下,抢价值最大的那一家
for(int index=2; index < result.length; index++){
result[index] = Math.max(nums[index] + result[index-2], result[index -1]);
}
return result[nums.length -1];
}
}
算法解析:
此题所采用的解法,和第一题“爬楼梯”有点类似,对于多个选择节点的问题,进行分解。对于数组长度为0、为1、为2的情况,按照题目要求进行讨论。对于长度超过2的数组,每一个结果数组的元素值,都建立在已得结果的基础上。对于n个住户,我们可以选择抢夺第一家,然后考虑第三家到最后一家,也可以直接从第二家开始抢夺。由于之前的n-2和n-1家的最佳结果已经存储到result数组中,因此这两种策略的收益分别对应:nums[index]+result[index-2]和result[index-1],我们可以选择其中的最大值,作为最终result[n]的结果。
最后,result[i]中存储的是:i户人家进行抢夺的最佳收益。
算法占用时空间资源:
补:
动态规划在这四题中,有两种不同的形式,一种是设置参考最值,遍历运算和参考最值比较(2和3),还有一种,是通过结果数组存储每一种结果(1和4),适合多选择结点的题目,选择方式往往可以用迭代思想进行拆解。