动态规划的规则
1.状态定义
2.固定住不确定的因素(例如1.确定连续子数组,我们可以选择固定子数组的末尾元素2.台阶确定最后一阶台阶),是得状态转移变得容易
3.求解过程中每个子问题只求解一次,无后效性。
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/fei-bo-na-qi-shu-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
对于斐波拉契数,我们可以选择使用递归方法,但是会超时。使用动态规划的实践复杂度为O(n).
递归代码如下:
public static int Fib(int n)
{
if (n == 0)
{
return 0;
}else if (n == 1)
{
return 1;
}
else
{
return Fib(n - 1) + Fib(n - 2);
}
}
动态规划代码如下:
public static int Fib1(int n)
{
if (n == 0)
{
return 0;
}
else if (n == 1)
{
return 1;
}
int a = 0;
int b = 1;
int c=0;
for(int i = 2; i <= n; i++)
{
c = (a + b) % 1000000007;
a = b;
b = c;
}
return c;
}
动态规划对于除余进行了处理。其他的均是动态规划思想,但是不是用数组去明确表示,而是使用了abc三个变量去对数组进行了表示。
动态规划的表格如下:
0 | 1 | 2 | 3 | 4 | 5 | |
dp | 0 | 1 | 1 | 2 | 3 | 5 |
对比此题的递归和动态规划,我们发现递归是从后往前(是栈),动态规划是从前往后(从小到大)。
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
示例 3:
输入:n = 0
输出:1
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/qing-wa-tiao-tai-jie-wen-ti-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public int NumWays(int n) {
if (n == 0)
{
return 1;
}else if (n == 1)
{
return 1;
}
int a = 1;
int b = 1;
int c=0;
for(int i = 2; i <= n; i++)
{
c = (a + b)% 1000000007;
a = b;
b = c;
}
return c;
}
此题跟上一题比较,初始条件变更而已。
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例 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。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/gu-piao-de-zui-da-li-run-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
7 | 1 | 5 | 3 | 6 | 4 | |
min | 7 | 1 | 1 | 1 | 1 | 1 |
maxProfit |
7-7=0 | 0 | 4 | 4 | 5 | 5 |
dp[i],确定的状态是以i天为结尾的时候,我们可以确定第i天卖股票,卖出价格,以及i天之前最低价格买入的价格。
min表示i天结尾的时候,最低买入价格。maxProfit表示最大利润。
代码为:
public static int MaxProfit(int[] prices)
{
int minPrice = prices[0];
int maxFrofix = 0;
for(int i = 0; i < prices.Length; i++)
{
if (minPrice > prices[i])
{
minPrice = prices[i];
}
maxFrofix = Math.Max(maxFrofix, prices[i] - minPrice);
}
Console.WriteLine(maxFrofix);
return maxFrofix;
}
在main方法中使用此语句:
MaxProfit(new int[] {7,1,5,3,6,4 });
结果为
5
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
nums | -2 | 1 | -3 | 4 | -1 | 2 | 1 | -5 | 4 | |
i为尾最大子数和 | -2 | 1 | -2 | 4 | 3 | 5 | 6 | 1 | 5 |
public static int MaxSubArray(int[] nums)
{
int MaxSubArraySum = nums[0];
int[] dp = new int[nums.Length];
dp[0] = nums[0];
if (nums.Length == 1)
{
return MaxSubArraySum;
}
for(int i = 1; i < nums.Length; i++)
{
dp[i] = Math.Max(dp[i - 1] + nums[i], nums[i]);
MaxSubArraySum = Math.Max(dp[i], MaxSubArraySum);
}
Console.WriteLine(MaxSubArraySum);
return MaxSubArraySum;
}
主函数使用如下:
MaxSubArray(new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 });
结果为
6