详解逻辑回归(Logistic Regression):原理、推导、实现与实战

引言:逻辑回归(Logistic Regression)是机器学习中经典的二分类算法,虽名为“回归”,实则属于分类模型。它凭借简单高效、可解释性强、泛化能力稳定的特点,在工业界(如风控建模、用户转化预测)和学术研究中被广泛应用。本文将从基础概念切入,深入剖析逻辑回归的数学原理、损失函数设计、参数求解过程,再通过Python手动实现与sklearn库实操验证,补充正则化优化、多分类拓展及实战注意事项,适合机器学习入门者及需要夯实分类算法基础的开发者阅读。

一、逻辑回归核心概念与定位

1.1 逻辑回归与线性回归的区别

线性回归的核心是拟合自变量与连续因变量的线性关系,输出结果为连续值;而逻辑回归针对**分类问题**,输出结果是样本属于某一类别的概率(范围0~1),再通过阈值判断类别。两者的核心差异如下:

对比维度

线性回归

逻辑回归

模型类型

回归模型(无监督)

分类模型(监督学习)

输出范围

(-∞, +∞) 连续值

[0, 1] 概率值

损失函数

均方误差(MSE)

交叉熵损失(Cross-Entropy)

适用场景

预测连续值(如房价、销量)

二分类/多分类(如风控、垃圾邮件识别)

1.2 逻辑回归的核心思想

逻辑回归的核心是“将线性回归的输出映射到[0,1]区间,转化为分类概率”。具体步骤:

  1. 设定阈值(通常为0.5),若( p ≥ 0.5 )则判定为正类,否则为负类。

通过Sigmoid函数将线性输出

( z )

映射为概率

( p )

,表示样本属于正类的概率;

先构建自变量的线性组合:

( z = w_0 + w_1x_1 + w_2x_2 + ... + w_dx_d = w^Tx )

(其中

( w_0 )

为偏置项,

( w )

为权重向量,

( x )

为特征向量);

二、核心数学原理:Sigmoid函数与概率建模

2.1 Sigmoid函数(激活函数)

Sigmoid函数(也叫Logistic函数)是逻辑回归的核心激活函数,其作用是将线性输出

( z )

(范围(-∞, +∞))压缩到[0,1]区间,满足概率的取值要求。

2.1.1 函数公式

sigma(z) = \frac{1}{1 + e^{-z}}

2.1.2 函数特性

可导性:导数公式简洁,便于后续梯度下降求解,导数为

( sigma'(z) = sigma(z)(1 - sigma(z)) )

边界特性:( z→+∞ )时,( sigma(z)→1 );( z→-∞ )时,( sigma(z)→0 );

( z=0 )

时,

( sigma(z)=0.5 )

单调性:当

( z )

增大时,

( sigma(z) )

单调递增,导数在

( z=0 )

时取得最大值0.25;

2.1.3 函数可视化

import numpy as np import matplotlib.pyplot as plt # 定义Sigmoid函数 def sigmoid(z): return 1 / (1 + np.exp(-z)) # 生成z值并计算对应的sigmoid结果 z = np.linspace(-10, 10, 1000) sigma_z = sigmoid(z) # 可视化 plt.figure(figsize=(8, 5)) plt.plot(z, sigma_z, 'b-', linewidth=2) plt.axvline(x=0, color='k', linestyle='--', alpha=0.5) # z=0辅助线 plt.axhline(y=0.5, color='k', linestyle='--', alpha=0.5) # 概率0.5辅助线 plt.xlabel('z = w^Tx') plt.ylabel('σ(z) (Probability)') plt.title('Sigmoid Function') plt.grid(True, alpha=0.3) plt.show()

2.2 概率建模与类别判定

逻辑回归通过Sigmoid函数构建样本属于正类(记为1)和负类(记为0)的概率模型:

负类概率:

( P(y=0|x;w) = 1 - sigma(w^Tx) = frac{e^{-w^Tx}}{1 + e^{-w^Tx}} )

正类概率:

( P(y=1|x;w) = sigma(w^Tx) = frac{1}{1 + e^{-w^Tx}} )

将两式合并为统一形式(似然函数的基础):

P(y|x;w) = [\sigma(w^Tx)]^y \cdot [1 - \sigma(w^Tx)]^{1-y}

类别判定规则:设定阈值

( threshold )

(默认0.5),若( P(y=1|x;w) ≥ threshold ),则预测为正类(y=1),否则为负类(y=0)。阈值可根据业务需求调整(如风控场景需提高正类阈值以降低误判率)。

三、损失函数设计与数学推导

逻辑回归无法直接使用线性回归的均方误差(MSE)作为损失函数——因为Sigmoid函数与MSE结合后,损失函数是非凸的,存在多个局部最小值,无法通过梯度下降找到全局最优解。因此,逻辑回归采用交叉熵损失函数(Cross-Entropy Loss),确保损失函数为凸函数,梯度下降可收敛到全局最优。

3.1 交叉熵损失函数(二分类)

3.1.1 单个样本的损失

对于单个样本

( (x_i, y_i) )

,损失函数定义为:

L(w; x_i, y_i) = -y_i \log(\sigma(w^Tx_i)) - (1 - y_i) \log(1 - \sigma(w^Tx_i))

解读:

( y_i=0 )

时,损失简化为

( -\log(1 - \sigma(w^Tx_i)) )

:若预测概率接近0,损失趋近于0;若接近1,损失趋近于+∞。

( y_i=1 )

时,损失简化为

( -\log(\sigma(w^Tx_i)) )

:若模型预测概率

( sigma(w^Tx_i) )

接近1,损失趋近于0;若接近0,损失趋近于+∞(惩罚力度大);

3.1.2 全局损失函数(所有样本)

全局损失为所有样本损失的平均值(也可求和,不影响梯度方向):

J(w) = \frac{1}{n} \sum_{i=1}^{n} \left[ -y_i \log(\sigma(w^Tx_i)) - (1 - y_i) \log(1 - \sigma(w^Tx_i)) \right]

逻辑回归的目标是最小化全局损失函数\( J(w) \),求解最优权重\( w \)。

3.2 梯度推导与参数求解(梯度下降法)

逻辑回归通过梯度下降法最小化损失函数,核心是计算损失函数对权重

( w )

的梯度,再沿梯度负方向更新权重。

3.2.1 梯度计算

对全局损失函数( J(w) )求关于权重

( w_j )

的偏导数(以单个特征权重为例):

  1. 梯度向量形式(便于批量计算):

其中

( X )

( n×(d+1) )

特征矩阵(含偏置项

( x_0=1 )

),

( y )

( n×1 )

标签向量,

( sigma(Xw) )

( n×1 )

预测概率向量。

代入Sigmoid函数导数特性

( \sigma'(z) = \sigma(z)(1 - \sigma(z)) )

,结合链式法则推导:

3.2.2 梯度下降更新规则

权重更新公式为(

( alpha )

为学习率,控制步长):

w = w - \alpha \cdot \nabla_w J(w) = w - \alpha \cdot \frac{1}{n} X^T (\sigma(Xw) - y)

迭代更新权重,直到梯度的绝对值小于预设阈值(收敛),或达到最大迭代次数,停止迭代并输出最优权重

( w )

3.2.3 学习率的影响

  • 学习率过小时:收敛速度慢,需要更多迭代次数;
  • 学习率过大时:可能跳过全局最小值,导致损失震荡不收敛;
  • 解决方案:采用自适应学习率(如AdaGrad、Adam),或逐步衰减学习率。

四、Python实现逻辑回归(手动实现+sklearn库)

以鸢尾花数据集(二分类任务,取前两类)为例,分别实现手动逻辑回归与sklearn库调用,验证模型效果。

4.1 环境准备

pip install numpy pandas matplotlib scikit-learn

4.2 手动实现逻辑回归(梯度下降)

import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 1. 数据加载与预处理(二分类任务) iris = load_iris() X = iris.data[:, :2] # 取前2个特征,便于可视化 y = iris.target # 筛选前两类(y=0和y=1),转为二分类问题 mask = (y == 0) | (y == 1) X = X[mask] y = y[mask] # 标准化(逻辑回归对量纲敏感,必须预处理) scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 添加偏置项x0=1(特征矩阵首列全为1) X_scaled = np.hstack([np.ones((X_scaled.shape[0], 1)), X_scaled]) # 划分训练集与测试集 X_train, X_test, y_train, y_test = train_test_split( X_scaled, y, test_size=0.3, random_state=42 ) # 2. 定义逻辑回归类(梯度下降实现) class LogisticRegressionManual: def __init__(self, learning_rate=0.01, max_iter=1000, tol=1e-4): self.lr = learning_rate # 学习率 self.max_iter = max_iter # 最大迭代次数 self.tol = tol # 收敛阈值 self.w = None # 权重参数(含偏置项) # Sigmoid函数 def sigmoid(self, z): # 避免指数溢出:z过大时e^-z趋近于0,z过小时e^-z趋近于+∞ z = np.clip(z, -100, 100) return 1 / (1 + np.exp(-z)) # 训练模型 def fit(self, X, y): n_samples, n_features = X.shape self.w = np.zeros(n_features) # 初始化权重为0 for _ in range(self.max_iter): # 计算线性输出z和预测概率 z = np.dot(X, self.w) y_pred_prob = self.sigmoid(z) # 计算梯度 gradient = np.dot(X.T, (y_pred_prob - y)) / n_samples # 判断收敛(梯度绝对值最大值小于阈值) if np.max(np.abs(gradient)) < self.tol: break # 更新权重 self.w -= self.lr * gradient # 预测(返回类别标签) def predict(self, X): z = np.dot(X, self.w) y_pred_prob = self.sigmoid(z) return np.where(y_pred_prob >= 0.5, 1, 0) # 3. 训练与评估 lr_manual = LogisticRegressionManual(learning_rate=0.1, max_iter=2000) lr_manual.fit(X_train, y_train) y_pred_manual = lr_manual.predict(X_test) # 计算准确率 acc_manual = accuracy_score(y_test, y_pred_manual) print(f"手动实现逻辑回归准确率:{acc_manual:.4f}") print(f"最优权重(含偏置项):{lr_manual.w}") # 4. 可视化决策边界 plt.figure(figsize=(8, 6)) # 绘制样本点 plt.scatter(X_test[:, 1], X_test[:, 2], c=y_test, cmap='viridis', edgecolors='black', label='True Label') # 绘制决策边界 (z=w0 + w1x1 + w2x2 = 0 → x2 = -(w0 + w1x1)/w2) x1 = np.linspace(X_test[:, 1].min(), X_test[:, 1].max(), 100) x2 = -(lr_manual.w[0] + lr_manual.w[1] * x1) / lr_manual.w[2] plt.plot(x1, x2, 'r-', label='Decision Boundary') plt.xlabel('Feature 1 (Standardized)') plt.ylabel('Feature 2 (Standardized)') plt.title('Logistic Regression (Manual Implementation)') plt.legend() plt.grid(True, alpha=0.3) plt.show()

4.3 sklearn库实现逻辑回归(工程首选)

sklearn的LogisticRegression类内置正则化、多分类支持、自适应求解器,适合实际项目使用,默认采用L2正则化和liblinear求解器。

from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report, confusion_matrix # 1. 数据预处理(同上,无需手动添加偏置项,sklearn自动处理) # X_train、X_test、y_train、y_test已在手动实现中定义 # 2. 初始化并训练模型(指定二分类,关闭正则化便于对比手动结果) lr_sklearn = LogisticRegression( penalty='none', # 关闭正则化 solver='liblinear', # 适合小样本二分类 random_state=42 ) lr_sklearn.fit(X_train[:, 1:], y_train) # 去掉手动添加的偏置项(sklearn自动处理) # 3. 预测与评估 y_pred_sklearn = lr_sklearn.predict(X_test[:, 1:]) acc_sklearn = accuracy_score(y_test, y_pred_sklearn) # 输出详细评估指标 print(f"sklearn逻辑回归准确率:{acc_sklearn:.4f}") print("分类报告:") print(classification_report(y_test, y_pred_sklearn)) print("混淆矩阵:") print(confusion_matrix(y_test, y_pred_sklearn)) # 输出模型参数(系数+偏置项) print(f"特征系数:{lr_sklearn.coef_}") print(f"偏置项:{lr_sklearn.intercept_}") # 4. 可视化决策边界(与手动实现对比) plt.figure(figsize=(8, 6)) plt.scatter(X_test[:, 1], X_test[:, 2], c=y_test, cmap='viridis', edgecolors='black', label='True Label') # 决策边界: w0 + w1x1 + w2x2 = 0 → x2 = -(w0 + w1x1)/w2 x1 = np.linspace(X_test[:, 1].min(), X_test[:, 1].max(), 100) x2 = -(lr_sklearn.intercept_[0] + lr_sklearn.coef_[0][0] * x1) / lr_sklearn.coef_[0][1] plt.plot(x1, x2, 'r-', label='Decision Boundary') plt.xlabel('Feature 1 (Standardized)') plt.ylabel('Feature 2 (Standardized)') plt.title('Logistic Regression (sklearn Implementation)') plt.legend() plt.grid(True, alpha=0.3) plt.show()

结果说明:手动实现与sklearn实现的准确率基本一致(接近1.0,因鸢尾花数据集前两类特征可分性强),权重参数也大致相同,验证了手动推导的正确性。

五、正则化:解决逻辑回归过拟合

当特征维度过高或样本量较小时,逻辑回归易出现过拟合(训练集准确率高,测试集准确率低)。正则化通过对权重施加惩罚,限制权重绝对值过大,从而降低模型复杂度,缓解过拟合。

5.1 常见正则化方式

5.1.1 L1正则化(Lasso)

在损失函数中添加权重绝对值之和的惩罚项,可实现特征选择(使部分权重变为0):

J(w) = \text{Cross-Entropy Loss} + \lambda \sum_{j=1}^{d} |w_j|

适用场景:特征维度高、存在冗余特征时。

5.1.2 L2正则化(Ridge)

在损失函数中添加权重平方和的惩罚项,使权重趋于平缓,不具备特征选择能力:

J(w) = \text{Cross-Entropy Loss} + \frac{\lambda}{2} \sum_{j=1}^{d} w_j^2

适用场景:大多数常规场景,是逻辑回归的默认正则化方式。

5.1.3 ElasticNet(L1+L2)

结合L1和L2正则化的优点,适合特征冗余且需保留部分关键特征的场景:

J(w) = \text{Cross-Entropy Loss} + \lambda_1 \sum_{j=1}^{d} |w_j| + \frac{\lambda_2}{2} \sum_{j=1}^{d} w_j^2

5.2 sklearn中正则化的使用

# L1正则化示例 lr_l1 = LogisticRegression( penalty='l1', # L1正则化 solver='liblinear', # L1正则化需搭配liblinear求解器 C=0.1, # 正则化强度倒数(C越小,正则化越强) random_state=42 ) lr_l1.fit(X_train[:, 1:], y_train) # L2正则化示例(默认) lr_l2 = LogisticRegression( penalty='l2', # L2正则化 solver='liblinear', C=0.1, random_state=42 ) lr_l2.fit(X_train[:, 1:], y_train) # 对比权重(L1会使部分权重趋近于0) print("L1正则化权重:", lr_l1.coef_) print("L2正则化权重:", lr_l2.coef_)

六、逻辑回归的多分类拓展

逻辑回归本质是二分类模型,通过“拆解为多个二分类任务”实现多分类,sklearn支持两种多分类策略:

6.1 One-vs-Rest(OvR,一对多)

核心思想:将每个类别视为正类,其余所有类别视为负类,训练K个二分类逻辑回归模型(K为类别数);预测时,选择概率最大的模型对应的类别作为结果。

优点:简单高效,适合类别数较多的场景;缺点:对不平衡数据敏感。

6.2 One-vs-One(OvO,一对一)

核心思想:每两个类别构建一个二分类模型,共训练

( C(K,2) = K(K-1)/2 )

个模型;预测时,通过投票确定最终类别(被预测为正类次数最多的类别获胜)。

优点:对不平衡数据鲁棒性强;缺点:模型数量多,计算成本高,适合类别数较少的场景。

6.3 sklearn多分类实现

# 使用完整鸢尾花数据集(3分类) X_full = iris.data y_full = iris.target X_full_scaled = scaler.fit_transform(X_full) X_train_full, X_test_full, y_train_full, y_test_full = train_test_split( X_full_scaled, y_full, test_size=0.3, random_state=42 ) # OvR策略(默认) lr_ovr = LogisticRegression( multi_class='ovr', # 多分类策略:OvR solver='liblinear', random_state=42 ) lr_ovr.fit(X_train_full, y_train_full) y_pred_ovr = lr_ovr.predict(X_test_full) # OvO策略 lr_ovo = LogisticRegression( multi_class='multinomial', # 多分类策略: OvO solver='lbfgs', # 需搭配 lbfgs/sag/saga求解器 random_state=42 ) lr_ovo.fit(X_train_full, y_train_full) y_pred_ovo = lr_ovo.predict(X_test_full) # 评估 print("OvR准确率:", accuracy_score(y_test_full, y_pred_ovr)) print("OvO准确率:", accuracy_score(y_test_full, y_pred_ovo))

七、逻辑回归的优缺点与应用场景

7.1 优点

  • 可解释性极强:权重\( w_j \)的正负表示特征对正类的影响方向,绝对值大小表示影响程度,便于业务解读(如风控模型中,某特征权重为正表示该特征值越大,违约风险越高);
  • 计算高效:训练和预测速度快,时间复杂度低,适合大规模数据集;
  • 泛化能力稳定:对噪声数据相对鲁棒(配合正则化),不易过拟合(相较于复杂模型);
  • 输出概率值:可获得样本属于某类别的置信度,便于业务决策(如设定不同阈值区分风险等级);
  • 工程落地简单:模型参数少,部署成本低,适合嵌入式、实时预测场景。

7.2 缺点

  • 线性假设局限:仅能捕捉特征与标签的线性关系,无法处理非线性数据(需手动构造多项式特征或结合特征工程);
  • 对异常值敏感:异常值会影响权重计算,需预处理时剔除或修正;
  • 对数据预处理要求高:需标准化、处理缺失值、类别特征编码(如独热编码),否则影响模型效果;
  • 难以处理高维稀疏数据:需结合特征选择或降维(如L1正则化、PCA)。

7.3 典型应用场景

  1. 风控建模:信用卡欺诈检测、贷款违约预测(输出违约概率,设定阈值决策);
  2. 用户行为预测:用户点击预测、转化预测、流失风险评估(如电商用户下单预测);
  3. 文本分类:垃圾邮件识别、舆情倾向判断(结合TF-IDF特征);
  4. 医疗诊断:基于症状特征判断疾病风险(如癌症早期筛查的概率输出);
  5. 推荐系统:辅助判断用户对物品的偏好,优化推荐策略。

八、实战技巧与常见问题

8.1 关键实战技巧

  • 特征预处理:必须标准化(消除量纲),缺失值用均值/中位数填充,类别特征需编码(独热编码适合无顺序类别,标签编码适合有顺序类别);
  • 特征工程:通过多项式特征、交互特征捕捉非线性关系,用L1正则化或特征选择剔除冗余特征;
  • 类别不平衡处理:采用过采样(SMOTE)、欠采样或调整类别权重(sklearn的class_weight参数);
  • 求解器选择:小样本二分类用liblinear,大样本/多分类用lbfgs/sag/saga;
  • 正则化调优:通过网格搜索(GridSearchCV)优化C值(正则化强度),平衡拟合能力与泛化能力。

8.2 常见问题与解决方案

  • 问题1:模型准确率低,拟合效果差? 解决方案:检查特征是否充分(增加有效特征)、是否存在非线性关系(构造多项式特征)、学习率是否合适(调大学习率或增加迭代次数)。
  • 问题2:训练集准确率高,测试集准确率低(过拟合)? 解决方案:添加正则化(L1/L2)、减少特征维度、增加样本量、处理异常值。
  • 问题3:模型不收敛,损失震荡? 解决方案:调整学习率(减小或采用自适应学习率)、标准化特征、检查数据是否存在多重共线性(剔除相关特征)。

九、总结与拓展

逻辑回归是机器学习分类算法的“入门基石”,其核心是通过Sigmoid函数将线性输出转化为概率,结合交叉熵损失与梯度下降求解最优参数。它虽结构简单,但可解释性和工程实用性极强,是工业界首选的基线模型。

针对逻辑回归的线性局限,可拓展学习以下算法:

  • 核逻辑回归(Kernel Logistic Regression):通过核函数将数据映射到高维空间,处理非线性问题;
  • 神经网络:通过多层感知机(MLP)自动学习非线性特征,是逻辑回归的深度拓展;
  • 梯度提升树(XGBoost/LightGBM):对非线性数据拟合能力更强,可作为复杂场景的进阶模型。

希望本文能帮助大家夯实逻辑回归的理论基础与工程实践能力,在实际项目中灵活运用并优化模型。如有疑问或补充,欢迎在评论区交流!

Read more

时间戳:CAN通信中的隐形时钟守护者

时间戳:CAN通信中的隐形时钟守护者 在现代嵌入式系统和实时控制应用中,精确的时间管理往往是系统可靠性的生命线。无论是自动驾驶车辆中多个传感器数据的毫秒级同步,还是工业生产线上的设备协同,时间戳都扮演着幕后英雄的角色。它不像通信协议那样引人注目,却默默地为系统提供着关键的时间参考,让分布式节点能够在同一时间维度上对话。对于嵌入式工程师和实时系统开发者来说,深入理解时间戳的机制和应用,是构建高可靠性系统的必备技能。 1. 时间戳的核心价值与生成机制 时间戳在CAN通信中本质上是一种元数据,它并不属于CAN协议本身定义的帧结构,而是由控制器硬件或系统软件附加的时序信息。当CAN控制器检测到总线上的完整数据帧时,会在帧被成功接收的瞬间记录当前的时间值,这个时间值就是时间戳。 时间戳的生成方式主要分为三种: * 硬件定时器时间戳:基于芯片内部的高精度定时器,通常在微秒或纳秒级别 * 系统时钟时间戳:使用操作系统的时钟源,精度取决于系统时钟配置 * 专用外设时间戳:某些高端CAN控制器内置专门的时间戳单元 在实际应用中,硬件生成的时间戳通常比软件生成的时间戳更加精确和可靠。因

【优选算法必刷100题】第007~008题(双指针算法):三数之和、四数之和问题求解

【优选算法必刷100题】第007~008题(双指针算法):三数之和、四数之和问题求解

🔥艾莉丝努力练剑:个人主页 ❄专栏传送门:《C语言》、《数据结构与算法》、C/C++干货分享&学习过程记录、Linux操作系统编程详解、笔试/面试常见算法:从基础到进阶 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬艾莉丝的算法专栏简介: 目录 007  三数之和 1.1  题目解析 1.2  思路1:暴力 1.3  思路2:排序 + 双指针 1.3.1  算法思路 1.3.2  代码实现 1.4  过程推算 1.5  反思 008  四数之和

【c-数据结构】顺序表 链表

一、线性表 1、线性表的基本概念 线性表(Linear List)是一种基本的数据结构,由一组具有相同数据类型的元素构成,这些元素按线性顺序排列。每个元素(除首尾外)均有唯一的前驱和后继元素。线性表的逻辑结构表现为一条“线”,元素之间是一对一的关系。线性表的特点主要有有限性、有序性、同质性。并且线性表在逻辑结构上连续的但在物理结构上不一定连续。 2、线性表的储存方式 <1>、顺序存储(顺序表) 使用连续的物理内存单元存储元素,通过数组实现。支持随机访问,但插入/删除需移动大量元素<2>、链式存储(链表) 通过节点(包含数据域和指针域)动态分配内存,节点间通过指针链接。插入/删除高效,但访问需遍历 3、常见线性表类型 <1>、顺序表:

【算法通关指南:算法基础篇】 一维前缀和专题: 1. 【模板】一维前缀和,2.最大子段和

【算法通关指南:算法基础篇】 一维前缀和专题: 1. 【模板】一维前缀和,2.最大子段和

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人方向学习者 ❄️个人专栏:《算法通关指南》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、前缀和 * 二、一维前缀和 * 2.1 核心问题 * 2.1.1 构建一维前缀和 * 2.2.2 利用前缀和数组求解区间【l,r】内元素的和 * 三、一维前缀和经典算法题 * 3.1【模板】前缀和 * 3.1.1题目 * 3.1.2 算法原理 * 3.1.3代码 * 3.2 最大子段和 * 3.

阿里云全品类 8 折券限时领,建站 / AI / 存储通用 立即领取