LeetCode-121. 买卖股票的最佳时机(121-I, 122-II, 123-III)

一、121. 买卖股票的最佳时机

1. 简介

参考: https://blog.csdn.net/qq_43498345/article/details/128308298

这个是只允许买卖一次。可以使用贪心算法。

2. 代码实现

复制代码
#include <stdio.h>

#define INT_MAX ((int)(~0u >> 1))
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))

int min_val(int x, int y) { return x < y ? x : y; }
int max_val(int x, int y) { return x > y ? x : y; }

/* 股票只能买卖一次的,使用贪心算法,求左侧的最小值与右侧的最大值 */
int max_profit(int *prices, int sz)
{
    int i;
    int min_price = INT_MAX;
    int max_profi = 0;

    for (i = 0; i < sz; i++) {
        min_price = min_val(min_price, prices[i]); //求最低价在前,已经可以表示买在前了
        max_profi = max_val(max_profi, prices[i] - min_price);
    }
    
    return max_profi;
}

int main()
{
    int prices[] = {7,1,5,3,6,4}; //5 匹配
    //int prices[] = {7,6,4,3,1}; //0 匹配

    printf("func1: max profit=%d\n", max_profit(prices, ARRAY_SIZE(prices))); //只单次买入卖出

    return 0;
}
复制代码


二、122. 买卖股票的最佳时机 II

1. 简介

参考:https://blog.csdn.net/qq_43498345/article/details/128308263

这次是可以买卖多次。

使用动态规划来解决,动态规划6要素:

(1) 确定dp递归数组、数组元素含义、下标含义。
dp[i][j] 表示此状态下手里最多钱的数量,i表示第i天,j=0表示没有持有,j=1表示持有。
(2) 确定递推公式
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) //第i天没有持有,取,之前一直没有持有,和之前持有状态但这一天把它卖了,的最大值。
dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1]) //第i天持有,取,之前一直没有持有但这一天买了,或之前一直是持有状态。
(3) dp数组如何初始化
可以看到与 dp[0][0] 和 dp[0][1] 有关。
dp[0][0] = 0; //假设一开始手里的钱数为0
dp[0][1] = -prices[0];
(4) 确定遍历顺序(从左到右/从右到左)
可以看到dp后一个与前一个有关,因此从左向右
(5) 确定返回值
(6) 举例推导dp数组。


2. 代码实现

复制代码
#include <stdio.h>

#define INT_MAX ((int)(~0u >> 1))
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))

int min_val(int x, int y) { return x < y ? x : y; }
int max_val(int x, int y) { return x > y ? x : y; }

/* 让自己的返回值变为最后操作的结果(dp[i][0] 表示持有,dp[i][1] 表示没有持有) */
int max_profit_2(int *prices, int sz)
{
    int i, j;
    int dp[32][2] = {{0}};

    dp[0][0] = -prices[0];
    dp[0][1] = 0;

    for (i = 1; i < sz; i++) {
        dp[i][0] = max_val(dp[i-1][0], dp[i-1][1] - prices[i]);
        dp[i][1] = max_val(dp[i-1][1], dp[i-1][0] + prices[i]);
    }

    return dp[sz-1][1]; //最后卖出了是没有持有状态,尽量将最后的运算结果作为返回结果。
}

int main()
{
    int prices[] = {7,1,5,3,6,4}; //5 匹配
    //int prices[] = {7,6,4,3,1}; //0 匹配
    //printf("func1: max profit=%d\n", max_profit(prices, ARRAY_SIZE(prices))); //上题的只单次买入卖出一次
    printf("func3: max profit=%d\n", max_profit_2(prices, ARRAY_SIZE(prices))); //本题执行了多次买入/卖出
    
    return 0;
}
复制代码

注:可以看到 dp[i] 只依赖于 dp[i-1], 因此可以使用滚动数组来降低空间复杂度,通过 dp[i % 2][X] 和 dp[(i - 1) % 2][X] 来实现,保存推导关系的只需要一个2x2的数组即可。


三、123. 买卖股票的最佳时机 III

1. 简介

参考:https://blog.csdn.net/qq_43498345/article/details/128323095

这个限制了,最大买卖两次。

这里仍然通过动态规划实现,注意推导的6大步骤。

一天一共就有五个状态,
[0]. 没有操作
[1]. 第一次买入
[2]. 第一次卖出
[3]. 第二次买入
[4]. 第二次卖出
dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。

注意:dp[i][1],表示的是第i天,买入股票的状态,并不是说一定要第i天买入股票,这是很多同学容易陷入的误区。


2. 代码

复制代码
#include <stdio.h>

#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))

int min_val(int x, int y) { return x < y ? x : y; }
int max_val(int x, int y) { return x > y ? x : y; }

#define PRICE_SIZE 8

int max_profit(int *prices, int sz)
{
    int i;
    int dp[PRICE_SIZE][5] = {{0}};

    if (sz == 0) return 0;

    dp[0][1] = dp[0][3] = -prices[0];

    for (i = 1; i < sz; i++) {
        dp[i][0] = dp[i - 1][0];
        /* 第i天没有操作沿用之前状态,与第i天执行了各种操作,取最大值. 可以看到每一步都与前一步有关 */
        dp[i][1] = max_val(dp[i - 1][1], dp[i - 1][0] - prices[i]); //第一次买入必须在没有任何操作的基础上
        dp[i][2] = max_val(dp[i - 1][2], dp[i - 1][1] + prices[i]); //第一次卖出必须在第一次买入的基础上
        dp[i][3] = max_val(dp[i - 1][3], dp[i - 1][2] - prices[i]); //第二次买入必须在第一次卖出的基础上
        dp[i][4] = max_val(dp[i - 1][4], dp[i - 1][3] + prices[i]); //第二次卖出必须在第二次买入的基础上
    }

    return dp[sz - 1][4];
}

int main()
{
    int prices[] = {3,3,5,0,0,3,1,4}; //6 成立
    //int prices[] = {7,6,4,3,1}; //0 成立
    //int prices[] = {1,2,3,4,5}; //4 成立
    //int prices[] = {1}; //0 成立
    //int prices[] = {1, 9}; //8 成立

    printf("max_profit=%d\n", max_profit(prices, ARRAY_SIZE(prices))); //6

    return 0;
}
复制代码

 

posted on   Hello-World3  阅读(6)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2019-02-18 Android USB Host框架
2019-02-18 Android USB gadget框架学习笔记

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示