代码随想录——动态规划之买卖股票的最佳时机

121.买卖股票的最佳时机(只能买卖一次)

121. 买卖股票的最佳时机

思路一:贪心

贪心策略:我们要得到最大利润,最好就是价格最低买入,价格最高卖出。具体的方法是在遍历prices数组时维护价格的最小值Min,当访问到prices[i],假设此时卖出,那么所能得到的最大利润为prices[i]-Min,对于i=0~pricesNums,取最大值。

代码一
int maxProfit(int* prices, int pricesSize) {
    int Min = prices[0];  // 初始化最低股价为第一天价格
    int ans = 0;          // 初始化最大利润为0

    for (int i = 1; i < pricesSize; i++) {  // 从第二天开始遍历
        // 计算当前卖出能获得的利润,并与历史最大值比较
        ans = fmax(prices[i] - Min, ans);   
        // 更新最低股价,确保Min始终是已遍历天数中的最小值
        Min = fmin(prices[i], Min);         
    }

    return ans;  // 返回最大利润
}
思路二:dp

1.定义状态

  • dp[i][0]:表示第 i持有股票 时的最大现金。
  • dp[i][1]:表示第 i不持有股票 时的最大现金。

2.初始化

  • dp[0][0] = -prices[0]:第 0 天持有股票,现金为负的股票价格(表示买入股票)。
  • dp[0][1] = 0:第 0 天不持有股票,现金为 0。

3.状态转移方程

  • 持有股票

    • 如果第 i 天持有股票,可能是前一天已经持有股票,或者第 i 天买入股票,即前i-1天买入或者第i天买入两种情况。

    d p [ i ] [ 0 ] = m a x ⁡ ( d p [ i − 1 ] [ 0 ] , − p r i c e s [ i ] ) dp[i][0]=max⁡(dp[i−1][0],−prices[i]) dp[i][0]=max(dp[i1][0],prices[i])

  • 不持有股票

    • 如果第 i 天不持有股票,可能是前一天已经不持有股票,或者第 i 天卖出股票,即前i-1天卖出或者第i天才卖出两种情况。

    d p [ i ] [ 1 ] = m a x ⁡ ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] + p r i c e s [ i ] ) dp[i][1]=max⁡(dp[i−1][1],dp[i−1][0]+prices[i]) dp[i][1]=max(dp[i1][1],dp[i1][0]+prices[i])

4.最终结果

  • 最终结果为 dp[pricesSize-1][1],即最后一天不持有股票时的最大现金,因为不持有股票手中的现金肯定更大。
代码二
#include <stdio.h>
#include <limits.h> // 用于 INT_MIN

int maxProfit(int* prices, int pricesSize) {
    if (pricesSize == 0) return 0; // 空数组直接返回0

    // 定义动态规划数组
    int dp[pricesSize][2];
    
    // 初始化
    dp[0][0] = -prices[0]; // 第0天持有股票
    dp[0][1] = 0;          // 第0天不持有股票

    // 动态规划递推
    for (int i = 1; i < pricesSize; i++) {
        // 第i天持有股票:前一天已经持有,或者第i天买入
        dp[i][0] = fmax(dp[i - 1][0], -prices[i]);
        // 第i天不持有股票:前一天已经不持有,或者第i天卖出
        dp[i][1] = fmax(dp[i - 1][1], dp[i - 1][0] + prices[i]);
    }

    // 返回最后一天不持有股票的最大现金
    return dp[pricesSize - 1][1];
}

122.买股票的最佳时机Ⅱ(可以买卖多次)

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

思路一:贪心

本题的贪心思路在前面的博客已经介绍了,可以点击链接查看。

代码随想录——贪心

思路二:dp

1.dp数组含义

定义一个二维数组 dp[i][j] 表示第 i 天结束时的最大利润,其中:

  • dp[i][0] 表示第 i 天结束时持有股票时的最大利润。
  • dp[i][1] 表示第 i 天结束时不持有股票时的最大利润。

2.初始状态

  • 第 0 天(i = 0):
    • 如果在第 0 天买入股票,那么 dp[0][0] = -prices[0],因为需要花费 prices[0] 元。
    • 如果第 0 天不进行交易,则 dp[0][1] = 0

3.状态转移方程

对于第 i 天(i ≥ 1),我们有两种状态的转移:

  1. 持有股票状态(dp[i][0]

    • 情况 1:保持昨天已经持有股票的状态,即 dp[i-1][0]
    • 情况 2:昨天没有股票,但今天买入了股票,因此利润为 dp[i-1][1] - prices[i]

    所以,转移方程为:
    d p [ i ] [ 0 ] = m a x ⁡ ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] − p r i c e s [ i ] ) dp[i][0]=max⁡(dp[i−1][0], dp[i−1][1]−prices[i]) dp[i][0]=max(dp[i1][0],dp[i1][1]prices[i])

    与上一题中的dp[i][0]=max⁡(dp[i−1][0],−prices[i])不同

  2. 不持有股票状态(dp[i][1]

    • 情况 1:保持昨天不持有股票的状态,即 dp[i-1][1]
    • 情况 2:昨天持有股票,今天卖出,因此利润为 dp[i-1][0] + prices[i]

    所以,转移方程为:
    d p [ i ] [ 1 ] = m a x ⁡ ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] + p r i c e s [ i ] ) dp[i][1]=max⁡(dp[i−1][1], dp[i−1][0]+prices[i]) dp[i][1]=max(dp[i1][1],dp[i1][0]+prices[i])

4.遍历与最终结果

我们从第 1 天开始,按照上面的状态转移方程逐步更新 dp[i][0]dp[i][1]。最后一天(pricesSize - 1)结束时,答案为 dp[pricesSize-1][1],因为不持有股票的状态才是真正的“平仓”,实现了利润。

代码
int maxProfit(int* prices, int pricesSize) {
    int dp[pricesSize][2];
    // 初始化:第0天的状态
    dp[0][0] = -prices[0];  // 买入股票
    dp[0][1] = 0;           // 不买股票

    // 从第1天开始遍历
    for (int i = 1; i < pricesSize; i++) {
        // 如果持有股票:要么继续持有,要么今天买入(必须之前没有股票)
        dp[i][0] = fmax(dp[i-1][0], dp[i-1][1] - prices[i]);
        // 如果不持有股票:要么继续不持有,要么今天卖出(之前持有股票)
        dp[i][1] = fmax(dp[i-1][0] + prices[i], dp[i-1][1]);
    }
    return dp[pricesSize-1][1];
}

123.买卖股票的最佳时机Ⅲ(至多买卖两次)

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

问题描述

给定一个数组 prices,其中 prices[i] 表示第 i 天的股票价格。允许最多进行两笔交易(一次买入和卖出为一次交易),求出能获得的最大利润。
注意:同一时间只能持有一只股票,即在买入前必须完成前一次卖出。

思路:dp

1.dp数组含义

定义一个二维数组 dp[i][j],其中 i 表示第 i 天,而 j 则表示当天的状态。
状态的含义如下:

  • dp[i][0]:不操作
    表示第 i 天未进行任何交易操作,该状态其实作为一个初始状态使用,初始值为 0
  • dp[i][1]:第一次持有股票
    表示在第 i 天经过第一次买入后持有股票的最大利润。
    初始状态为:dp[0][1] = -prices[0](买入股票花费 prices[0])。
  • dp[i][2]:第一次不持有股票(完成第一次卖出)
    表示在第 i 天完成第一次交易(卖出后)获得的最大利润。
    初始状态为:dp[0][2] = 0
  • dp[i][3]:第二次持有股票
    表示在完成第一次交易之后,第二次买入后持有股票的状态。
    初始状态为:dp[0][3] = -prices[0](虽然一般来说第二次买入应该依赖于第一次卖出的收益,这里用 -prices[0] 进行初始化,后续会不断更新)。
  • dp[i][4]:第二次不持有股票(完成第二次卖出)
    表示在第 i 天完成第二笔交易后的最大利润。
    初始状态为:dp[0][4] = 0

2.状态转移公式

不操作状态:
d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] dp[i][0]=dp[i−1][0] dp[i][0]=dp[i1][0]
保持上一天的状态不变。

第一次持有状态:
当天可以选择买入股票,也可以保持之前的状态。

  • 如果今天买入股票,则利润为前一天的“不操作状态”减去当前价格:
    dp[i−1][0]−prices[i]

  • 或者保持昨天已经买入的状态:
    dp[i−1][1]
    故:
    d p [ i ] [ 1 ] = m a x ⁡ ( d p [ i − 1 ] [ 0 ] − p r i c e s [ i ] , d p [ i − 1 ] [ 1 ] ) dp[i][1]=max⁡(dp[i−1][0]−prices[i], dp[i−1][1]) dp[i][1]=max(dp[i1][0]prices[i],dp[i1][1])

第一次卖出状态(第一次不持有):
当天可以选择卖出第一次买入的股票,或者保持之前的状态。

  • 卖出后利润为:
    dp[i−1][1]+prices[i]
  • 或者保持之前卖出后的状态:
    dp[i−1][2]
    故:

d p [ i ] [ 2 ] = m a x ⁡ ( d p [ i − 1 ] [ 1 ] + p r i c e s [ i ] , d p [ i − 1 ] [ 2 ] ) dp[i][2]=max⁡(dp[i−1][1]+prices[i], dp[i−1][2]) dp[i][2]=max(dp[i1][1]+prices[i],dp[i1][2])

第二次持有状态:
第二次买入股票可在第一次卖出后进行。

  • 如果今天买入股票,则利润为第一次卖出后的利润减去当前价格:
    dp[i−1][2]−prices[i]
  • 或者保持之前的第二次买入状态:
    dp[i−1][3]
    故:

d p [ i ] [ 3 ] = m a x ⁡ ( d p [ i − 1 ] [ 2 ] − p r i c e s [ i ] , d p [ i − 1 ] [ 3 ] ) dp[i][3]=max⁡(dp[i−1][2]−prices[i], dp[i−1][3]) dp[i][3]=max(dp[i1][2]prices[i],dp[i1][3])

第二次卖出状态(第二次不持有):
当天可以选择卖出第二次买入的股票,或者保持之前的状态。

  • 卖出后利润为:
    dp[i−1][3]+prices[i]
  • 或者保持之前的状态:
    dp[i−1][4]
    故:

d p [ i ] [ 4 ] = m a x ⁡ ( d p [ i − 1 ] [ 3 ] + p r i c e s [ i ] , d p [ i − 1 ] [ 4 ] ) dp[i][4]=max⁡(dp[i−1][3]+prices[i], dp[i−1][4]) dp[i][4]=max(dp[i1][3]+prices[i],dp[i1][4])

3.最终结果

在最后一天,可能完成了一笔交易(状态 dp[n-1][2])或者完成了两笔交易(状态 dp[n-1][4])。因此最终答案为这两者中的最大值:
r e s u l t = m a x ⁡ ( d p [ p r i c e s S i z e − 1 ] [ 2 ] , d p [ p r i c e s S i z e − 1 ] [ 4 ] ) result=max⁡(dp[pricesSize−1][2], dp[pricesSize−1][4]) result=max(dp[pricesSize1][2],dp[pricesSize1][4])

代码
int maxProfit(int* prices, int pricesSize) {
    // 定义二维数组 dp,用于保存每一天的五种状态的最大利润
    int dp[pricesSize][5];
    
    // 初始化第 0 天的状态
    dp[0][0] = 0;              // 状态 0:不操作,利润为 0
    dp[0][1] = -prices[0];       // 状态 1:第一次买入,花费 prices[0]
    dp[0][2] = 0;              // 状态 2:第一次卖出尚未发生,利润为 0
    dp[0][3] = -prices[0];       // 状态 3:第二次买入的初始值(后续更新会修正)
    dp[0][4] = 0;              // 状态 4:第二次卖出尚未发生,利润为 0

    // 从第 1 天开始,依次更新每一天的状态
    for (int i = 1; i < pricesSize; i++) {
        // 状态 0:不操作状态保持不变
        dp[i][0] = dp[i-1][0];

        // 状态 1:第一次买入
        // 可能选择在当天买入,或者保持昨天买入的状态:
        //   - 买入:使用不操作状态 dp[i-1][0] 并减去今天的价格 prices[i]
        //   - 保持:延续昨天的第一次买入状态 dp[i-1][1]
        dp[i][1] = fmax(dp[i-1][0] - prices[i], dp[i-1][1]);

        // 状态 2:第一次卖出
        // 可能选择在当天卖出,或者保持昨天卖出的状态:
        //   - 卖出:将昨天的第一次买入状态 dp[i-1][1] 加上今天的价格 prices[i]
        //   - 保持:延续昨天的第一次卖出状态 dp[i-1][2]
        dp[i][2] = fmax(dp[i-1][1] + prices[i], dp[i-1][2]);

        // 状态 3:第二次买入
        // 可能选择在当天进行第二次买入,或者保持昨天的第二次买入状态:
        //   - 买入:使用昨天的第一次卖出状态 dp[i-1][2] 减去今天的价格 prices[i]
        //   - 保持:延续昨天的第二次买入状态 dp[i-1][3]
        dp[i][3] = fmax(dp[i-1][2] - prices[i], dp[i-1][3]);

        // 状态 4:第二次卖出
        // 可能选择在当天卖出,或者保持昨天的第二次卖出状态:
        //   - 卖出:将昨天的第二次买入状态 dp[i-1][3] 加上今天的价格 prices[i]
        //   - 保持:延续昨天的第二次卖出状态 dp[i-1][4]
        dp[i][4] = fmax(dp[i-1][3] + prices[i], dp[i-1][4]);
    }
    
    // 返回最后一天完成一次交易或两次交易中获得的最大利润
    return fmax(dp[pricesSize-1][2], dp[pricesSize-1][4]);
}

188.买卖股票的最佳时机Ⅳ(至多买卖k次)

188. 买卖股票的最佳时机 IV

思路:dp

上一题(123. 买卖股票的最佳时机 III)是本题k=2的特殊情况,如何上题理解的化,那么本题可以将2扩展至k。具体看代码。

代码
#include <stdio.h>
#include <limits.h>
#include <math.h>

int maxProfit(int k, int* prices, int pricesSize) {
    // 创建二维数组 dp[pricesSize][2*k+1]
    // dp[i][j] 表示第 i 天处于状态 j 时的最大利润
    int dp[pricesSize][2 * k + 1];

    // 初始化第 0 天的状态
    dp[0][0] = 0; // 状态 0:不操作,利润为 0
    // 初始化状态 1 ~ 2*k
    for (int j = 1; j <= 2 * k; j++) {
        // 如果 j 为奇数,表示买入状态:初始利润为 -prices[0]
        // 如果 j 为偶数,表示卖出状态:初始利润为 0
        if (j & 1)
            dp[0][j] = -prices[0];
        else
            dp[0][j] = 0;
    }

    // 从第 1 天开始,更新每一天的状态
    for (int i = 1; i < pricesSize; i++) {
        // 状态 0:不操作,直接继承前一天的值
        dp[i][0] = dp[i - 1][0];
        
        // 对于状态 1 到 2*k
        for (int j = 1; j <= 2 * k; j++) {
            // 如果 j 为奇数,表示买入状态
            if (j & 1)
                // 选择:
                // 1. 今天买入:前一天处于 j-1 状态(卖出状态)的利润减去今天价格
                // 2. 或者保持昨天买入的状态(不操作)
                dp[i][j] = fmax(dp[i - 1][j - 1] - prices[i], dp[i - 1][j]);
            else
                // 如果 j 为偶数,表示卖出状态
                // 选择:
                // 1. 今天卖出:前一天处于 j-1 状态(买入状态)的利润加上今天价格
                // 2. 或者保持昨天的卖出状态(不操作)
                dp[i][j] = fmax(dp[i - 1][j - 1] + prices[i], dp[i - 1][j]);
        }
    }
    
    // 答案在最后一天的各个卖出状态中取最大值
    // 卖出状态对应偶数下标:2, 4, ..., 2*k
    int ans = 0;
    for (int i = 1; i <= k; i++) {
        ans = fmax(ans, dp[pricesSize - 1][2 * i]);
    }
    return ans;
}

309.买卖股票的最佳时机含冷冻期

309. 买卖股票的最佳时机含冷冻期

题目描述

给定一个数组 prices,其中 prices[i] 表示第 i 天的股票价格。
设计一个算法,计算在存在“冷冻期”约束下的最大利润。
“冷冻期”约束说明:在卖出股票后的第二天处于冷冻状态,在冷冻状态下不能买入股票。

思路:dp

1.dp数组含义

用二维dp数组表示状态,对于dp[i][j]

  • i 表示第 i 天(从 0 开始计数)。
  • j 表示当天的状态,共有 4 种状态,每个状态的含义如下:
    1. dp[i][0] —— 持有股票
      表示第 i 天结束时持有股票的最大利润(买入后持有,未卖出)。
    2. dp[i][1] —— 当天卖出股票
      表示第 i 天卖出股票后得到的最大利润,即当天刚卖出股票。
    3. dp[i][2] —— 自由状态(未持有股票且非冻结)
      表示第 i 天未持有股票且没有受到冷冻期限制的状态,处于可以买入的自由状态。
    4. dp[i][3] —— 冻结状态
      表示第 i 天处于冻结状态,这通常是由于昨天卖出了股票,所以今天不能立即买入股票。

2.状态转移的解释

对于每天的状态更新,我们根据前一天的状态进行转移:

1.状态 0:持有股票
第 i 天若要保持或进入持有股票状态,可以有以下三种情况:

  • 继续持有:如果昨天已经持有股票,则利润为 dp[i-1][0]
  • 从自由状态买入:如果昨天处于自由状态(dp[i-1][2]),则今天买入股票后利润为 dp[i-1][2] - prices[i]
  • 从冻结状态买入:如果昨天处于冻结状态(dp[i-1][3]),今天买入股票后利润为 dp[i-1][3] - prices[i]

因此,状态转移公式为:
d p [ i ] [ 0 ] = m a x ⁡ ( d p [ i − 1 ] [ 0 ] ,    d p [ i − 1 ] [ 2 ] − p r i c e s [ i ] ,    d p [ i − 1 ] [ 3 ] − p r i c e s [ i ] ) dp[i][0]=max⁡(dp[i−1][0],  dp[i−1][2]−prices[i],  dp[i−1][3]−prices[i]) dp[i][0]=max(dp[i1][0],  dp[i1][2]prices[i],  dp[i1][3]prices[i])
2.状态 1:当天卖出股票
要在第 i 天卖出股票,必须前一天处于持有状态(dp[i-1][0]),当天卖出获得收益:
d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + p r i c e s [ i ] dp[i][1]=dp[i−1][0]+prices[i] dp[i][1]=dp[i1][0]+prices[i]

3.状态 2:自由状态(未持有且非冻结)
第 i 天处于自由状态有两种来源:

  • 保持自由:如果昨天已经处于自由状态,则利润为 dp[i-1][2]
  • 冻结结束:如果昨天处于冻结状态,今天冷冻期结束,变为自由状态,则利润为 dp[i-1][3]

因此,状态转移公式为:
d p [ i ] [ 2 ] = m a x ⁡ ( d p [ i − 1 ] [ 2 ] ,    d p [ i − 1 ] [ 3 ] ) dp[i][2]=max⁡(dp[i−1][2],  dp[i−1][3]) dp[i][2]=max(dp[i1][2],  dp[i1][3])
4.状态 3:冻结状态
冻结状态通常由昨天刚卖出股票转移而来:
d p [ i ] [ 3 ] = d p [ i − 1 ] [ 1 ] dp[i][3]=dp[i−1][1] dp[i][3]=dp[i1][1]

代码
#include <limits.h>
#include <math.h>

/*
 * 题目:带冷冻期的股票交易问题
 *
 * dp 数组含义:
 *   dp[i][0]:第 i 天持有股票(买入后未卖出)的最大利润
 *   dp[i][1]:第 i 天卖出股票(当天刚卖出)的最大利润
 *   dp[i][2]:第 i 天未持有股票且处于自由状态(无冷冻限制)的最大利润
 *   dp[i][3]:第 i 天处于冻结状态(昨天卖出,今天冻结)的最大利润
 *
 * 状态转移:
 *   1. dp[i][0] = max(继续持有股票, 自由状态买入, 冻结状态买入)
 *       = max(dp[i-1][0], dp[i-1][2] - prices[i], dp[i-1][3] - prices[i])
 *
 *   2. dp[i][1] = dp[i-1][0] + prices[i]
 *
 *   3. dp[i][2] = max(保持自由状态, 冻结结束转为自由状态)
 *       = max(dp[i-1][2], dp[i-1][3])
 *
 *   4. dp[i][3] = dp[i-1][1]
 *
 * 最终答案:
 *   返回最后一天未持有股票的状态中的最大值:
 *   max(dp[n-1][1], dp[n-1][2], dp[n-1][3])
 */

int maxProfit(int* prices, int pricesSize) {
    // 定义 dp 数组,行数为天数,列数为 4 个状态
    int dp[pricesSize][4];
    
    // 初始化第 0 天的状态
    dp[0][0] = -prices[0];  // 第 0 天买入股票,持有股票
    dp[0][1] = 0;           // 第 0 天不可能卖出股票
    dp[0][2] = 0;           // 第 0 天未持有股票且非冻结状态
    dp[0][3] = 0;           // 第 0 天没有冻结状态
    
    // 从第 1 天开始,根据前一天的状态更新当天状态
    for (int i = 1; i < pricesSize; i++) {
        // 状态 0:持有股票
        dp[i][0] = fmax(fmax(dp[i-1][0], dp[i-1][2] - prices[i]), dp[i-1][3] - prices[i]);
        
        // 状态 1:当天卖出股票(只能从前一天持有股票卖出)
        dp[i][1] = dp[i-1][0] + prices[i];
        
        // 状态 2:自由状态(未持有且非冻结),可由前一天自由或冻结状态转移
        dp[i][2] = fmax(dp[i-1][2], dp[i-1][3]);
        
        // 状态 3:冻结状态,由前一天卖出股票转移而来
        dp[i][3] = dp[i-1][1];
    }
    
    // 最终答案:最后一天未持有股票的最大利润(可能是卖出、自由或冻结状态)
    return fmax(fmax(dp[pricesSize-1][1], dp[pricesSize-1][2]), dp[pricesSize-1][3]);
}

714.买股票的最佳时机含手续费

714. 买卖股票的最佳时机含手续费

思路:dp

122. 买卖股票的最佳时机 II的思路类似,不同点是本题在卖出股票的时候要减去手续费,其他都一样,即
d p [ i ] [ 1 ] = m a x ⁡ ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] + p r i c e s [ i ] − f e e ) dp[i][1]=max⁡(dp[i−1][1], dp[i−1][0]+prices[i]-fee) dp[i][1]=max(dp[i1][1],dp[i1][0]+prices[i]fee)

代码
int maxProfit(int* prices, int pricesSize, int fee) {
    // 定义 dp 数组,dp[i][0] 表示第 i 天持有股票的最大利润,
    // dp[i][1] 表示第 i 天不持有股票的最大利润
    int dp[pricesSize][2];
    
    // 初始化第 0 天的状态
    dp[0][0] = -prices[0];  // 第 0 天买入股票,持有股票,利润为 -prices[0]
    dp[0][1] = 0;           // 第 0 天不持有股票,利润为 0
    
    // 从第 1 天开始,根据前一天的状态更新今天的状态
    for (int i = 1; i < pricesSize; i++) {
        // 状态 0:持有股票
        // 可能选择继续持有或从不持有状态转为买入股票
        dp[i][0] = fmax(dp[i-1][0], dp[i-1][1] - prices[i]);
        
        // 状态 1:不持有股票
        // 可能选择继续不持有或卖出持有的股票(支付手续费)
        dp[i][1] = fmax(dp[i-1][1], dp[i-1][0] + prices[i] - fee);
    }
    
    // 返回最后一天不持有股票的最大利润
    return dp[pricesSize-1][1];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值