力扣网编程121题:买卖股票的最佳时机之动态规划(简单)

一. 简介

前一篇文章使用贪心算法实现了力扣网上121题:买卖股票的最佳时机,文章如下:

力扣网编程189题:买卖股票的最佳时机之贪心算法(简单)-CSDN博客

本文使用动态规划实现 该题目。

二. 力扣网编程189题:买卖股票的最佳时机之动态规划(简单)

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

解题思路二:(动态规划)

初步分析:

"买卖股票的最佳时机"问题要求:在给定的数组股票价格中,选择一天买入和之后的某一天卖出,使得利润最大(卖出价-买入价);如果利润<=0,则利润为0;

利润最大 和 "连续子数组和"的等效性

定义一个数组 diff,其中每个元素为 diff[i] = diff[i+1]-diff[i],指的是每天与前一天的差价。

假设在第 i 天买入,第j天卖出(j > i),则总利润为:prices[j] - prices[i],这个利润可以拆分为连续价格差的和

prices[j] - prices[i]:
= (prices[i+1]-prices[i])+(prices[i+2]-prices[i+1])+...+(prices[j]-prices[j-1])
= diff[i] + diff[i+1]+...+diff[j-1]

总结:从i到 j 的利润,也就等于 diff数组中(即价格差分数组)从 i到 j-1的连续子数组的和;

问题转化:

原问题是 “寻找 i < j 使得 prices[j] - prices[i] 最大”,等价于:
在 diff 数组中寻找一个连续子数组,使得其和最大(若最大和为负,则利润为 0)。
例如:
 prices[6] = [7,1,5,3,6,4],对应的价格差分数组diff:
diff 数组 [-6,4,-2,3,-2] 的最大连续子数组是 [4,-2,3],和为 5,对应原问题的最大利润 5(1 买入,6 卖出)。

具体方法:

1. 首先,算法维护两个变量:

current_max:当前连续子数组和(在价格差数组diff中)局部最优;

global_max:全局最大子数组和(全局最优);

2. 遍历数组prices,计算 价格差值 diff[i];判断 价格差diff 和 current_max+diff,决定是从当前天重新开始算,还是延续之前的利润链?

diff > current_max+diff,则 current_max = diff;

diff < current_max +diff,则 current_max = current_max +diff;

3. 更新全局最大利益 global_max值,和 current_max比较决定是否更新。遍历完成返回  global_max;

C语言实现如下:


//动态规划
// “寻找 i < j 使得 prices[j] - prices[i] 最大”,等价于:
//在价格差数组中寻找一个连续子数组和最大
int maxProfit(int* prices, int pricesSize) {
    //处理特殊情况
    if(pricesSize <= 1) {
        return 0;
    }

    int i;
    //当前最大利润(以当前元素结尾的最大子数组和)
    int current_max = 0;
    //全局最大利润(遍历过程中遇到的最大利润)
    int global_max = 0;
    //从第二天算起,计算每天的价格差
    for(i = 1; i < pricesSize; i++ ) {
        //计算价格差值
        int diff = prices[i]-prices[i-1];

        // 更新当前最大利润:
        // 1. 要么从当前天重新开始(只取当前差值diff)
        // 2. 要么延续之前的利润链(current_max + diff)
        current_max = diff > (diff+current_max)? diff: (diff+current_max);

        if(current_max > global_max) {
            global_max = current_max;
        }
    }
    return global_max;
}

可以看出,动态规划这种解法的时间复杂度为O(n),空间复杂度为O(1)。

你可能感兴趣的:(逻辑编程题,C语言,leetcode,动态规划,算法)