从零构建逻辑回归: sklearn 与自定义实现对比
文章目录
- 理论基础
- 1. 逻辑回归模型
- 2. 损失函数
- 3. 梯度推导
- (1) 计算 ∂ L ∂ y ^ \frac{\partial L}{\partial \hat{y}} ∂y^∂L
- (2) 计算 ∂ y ^ ∂ z \frac{\partial \hat{y}}{\partial z} ∂z∂y^
- (3) 计算 ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L
- (4) 计算 ∂ z ∂ w \frac{\partial z}{\partial w} ∂w∂z 和 ∂ z ∂ b \frac{\partial z}{\partial b} ∂b∂z
- (5) 计算 ∂ L ∂ w \frac{\partial L}{\partial w} ∂w∂L 和 ∂ L ∂ b \frac{\partial L}{\partial b} ∂b∂L
- 4. 梯度下降
- 梯度下降的执行步骤:
- 5. 总结
- 项目结构
- 代码实现
- 1. `my_sklearn/linear_model/logistic_regression.py` — 自定义逻辑回归实现
- 2. `my_sklearn/metrics/accuracy.py` — 自定义准确率计算
- 3. `my_sklearn/linear_model/__init__.py` — 导出 `MyLogisticRegression`
- 4. `my_sklearn/metrics/__init__.py` — 导出准确率函数
- 5. `my_sklearn/__init__.py` — 主包初始化
- 6. `main.py` — 主程序文件,包含数据处理和模型对比
- 项目使用说明
- 总结
尽管名字中有“回归”二字,逻辑回归(Logistic Regression)实际上是一种分类方法,主要用于二分类问题。它通过一个线性模型与 Sigmoid 函数的结合,将问题转化为一个概率预测问题,并基于该概率来做分类决策。下面将详细讲解逻辑回归的工作原理、损失函数、梯度推导、以及如何通过梯度下降来优化模型。
这篇文章也写的不错:
Python实现逻辑回归(Logistic Regression)
理论基础
1. 逻辑回归模型
逻辑回归的核心是 Sigmoid 函数,也称为 逻辑函数。它可以将任何实数值映射到区间 [0, 1] 内,因此非常适合用于概率预测。Sigmoid 函数的形式为:
σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
其中 (z) 是线性回归的输出,可以表示为:
z = w T x + b z = w^T x + b z=wTx+b
这里:
- w w w 是权重向量(模型参数之一),
- x x x 是输入特征向量,
- b b b 是偏置项。
因此,Sigmoid 函数的输出 y ^ = σ ( z ) \hat{y} = \sigma(z) y^=σ(z) 表示样本属于正类(即 y = 1 y = 1 y=1)的概率。对于二分类问题,模型的目标是预测输入样本属于类别1的概率:
P ( y = 1 ∣ x ) = σ ( w T x + b ) P(y = 1 | x) = \sigma(w^T x + b) P(y=1∣x)=σ(wTx+b)
如果 y ^ ≥ 0.5 \hat{y} \geq 0.5 y^≥0.5,则预测样本为正类 y = 1 y = 1 y=1,否则预测为负类 y = 0 y = 0 y=0。
2. 损失函数
逻辑回归使用 交叉熵损失函数(Cross-Entropy Loss)来衡量模型的预测与真实标签之间的差异。交叉熵损失函数的形式如下:
L ( y , y ^ ) = − [ y log ( y ^ ) + ( 1 − y ) log ( 1 − y ^ ) ] L(y, \hat{y}) = - \left[ y \log(\hat{y}) + (1 - y) \log(1 - \hat{y}) \right] L(y,y^)=−[ylog(y^)+(1−y)log(1−y^)]
其中:
- y y y 是真实标签(0 或 1),
- y ^ \hat{y} y^ 是模型预测的概率。
对于整个训练集,损失函数 J ( w , b ) J(w, b) J(w,b) 是所有样本损失的平均值,具体形式为:
J ( w , b ) = − 1 m ∑ i = 1 m [ y ( i ) log ( y ^ ( i ) ) + ( 1 − y ( i ) ) log ( 1 − y ^ ( i ) ) ] J(w, b) = -\frac{1}{m} \sum_{i=1}^m \left[ y^{(i)} \log(\hat{y}^{(i)}) + (1 - y^{(i)}) \log(1 - \hat{y}^{(i)}) \right] J(w,b)=−m1i=1∑m[y(i)log(y^(i))+(1−y(i))log(1−y^(i))]
其中 m m m 是训练集中的样本数量。
3. 梯度推导
为了优化逻辑回归模型,我们需要通过梯度下降算法最小化损失函数。首先,我们需要计算损失函数相对于模型参数 w w w 和 b b b 的梯度。
(1) 计算 ∂ L ∂ y ^ \frac{\partial L}{\partial \hat{y}} ∂y^∂L
损失函数对预测值的导数为:
∂ L ∂ y ^ = − ( y y ^ − 1 − y 1 − y ^ ) \frac{\partial L}{\partial \hat{y}} = -\left( \frac{y}{\hat{y}} - \frac{1 - y}{1 - \hat{y}} \right) ∂y^∂L=−(y^y−1−y^1−y)
(2) 计算 ∂ y ^ ∂ z \frac{\partial \hat{y}}{\partial z} ∂z∂y^
Sigmoid 函数的导数为:
∂ y ^ ∂ z = y ^ ( 1 − y ^ ) \frac{\partial \hat{y}}{\partial z} = \hat{y} (1 - \hat{y}) ∂z∂y^=y^(1−y^)
(3) 计算 ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L
根据链式法则,可以得到:
∂ L ∂ z = ∂ L ∂ y ^ ⋅ ∂ y ^ ∂ z = y ^ − y \frac{\partial L}{\partial z} = \frac{\partial L}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial z} = \hat{y} - y ∂z∂L=∂y^∂L⋅∂z∂y^=y^−y
(4) 计算 ∂ z ∂ w \frac{\partial z}{\partial w} ∂w∂z 和 ∂ z ∂ b \frac{\partial z}{\partial b} ∂b∂z
线性回归的输出对权重和偏置的导数为:
∂ z ∂ w = x , ∂ z ∂ b = 1 \frac{\partial z}{\partial w} = x, \quad \frac{\partial z}{\partial b} = 1 ∂w∂z=x,∂b∂z=1
(5) 计算 ∂ L ∂ w \frac{\partial L}{\partial w} ∂w∂L 和 ∂ L ∂ b \frac{\partial L}{\partial b} ∂b∂L
根据链式法则:
∂ L ∂ w = ( y ^ − y ) ⋅ x \frac{\partial L}{\partial w} = (\hat{y} - y) \cdot x ∂w∂L=(y^−y)⋅x
∂ L ∂ b = y ^ − y \frac{\partial L}{\partial b} = \hat{y} - y ∂b∂L=y^−y
对于整个训练集,梯度是所有样本梯度的平均值:
∂ J ∂ w = 1 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) ⋅ x ( i ) \frac{\partial J}{\partial w} = \frac{1}{m} \sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)}) \cdot x^{(i)} ∂w∂J=m1i=1∑m(y^(i)−y(i))⋅x(i)
∂ J ∂ b = 1 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) \frac{\partial J}{\partial b} = \frac{1}{m} \sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)}) ∂b∂J=m1i=1∑m(y^(i)−y(i))
4. 梯度下降
梯度下降是一种优化算法,用于最小化损失函数并学习最佳的模型参数。梯度下降的更新规则如下:
w : = w − α ∂ J ∂ w w := w - \alpha \frac{\partial J}{\partial w} w:=w−α∂w∂J
b : = b − α ∂ J ∂ b b := b - \alpha \frac{\partial J}{\partial b} b:=b−α∂b∂J
其中, α \alpha α 是学习率,控制每次更新的步长。
梯度下降的执行步骤:
- 初始化参数 w w w 和 b b b。
- 计算损失函数 J ( w , b ) J(w, b) J(w,b)。
- 计算梯度 ∂ J ∂ w \frac{\partial J}{\partial w} ∂w∂J 和 ∂ J ∂ b \frac{\partial J}{\partial b} ∂b∂J。
- 更新参数:
w : = w − α ∂ J ∂ w w := w - \alpha \frac{\partial J}{\partial w} w:=w−α∂w∂J
b : = b − α ∂ J ∂ b b := b - \alpha \frac{\partial J}{\partial b} b:=b−α∂b∂J - 重复步骤 2-4,直到损失函数收敛或达到最大迭代次数。
5. 总结
逻辑回归通过将线性回归的结果通过 Sigmoid 函数转化为概率,并使用交叉熵损失函数来衡量模型的误差。通过反向传播计算梯度,并利用梯度下降优化参数,逻辑回归模型可以逐步学习到最优的分类边界,适用于二分类问题。
项目结构
project_root/
├── my_sklearn/
│ ├── linear_model/
│ │ ├── __init__.py
│ │ └── logistic_regression.py
│ ├── metrics/
│ │ ├── __init__.py
│ │ └── accuracy.py
│ └── __init__.py
└── main.py
代码实现
1. my_sklearn/linear_model/logistic_regression.py — 自定义逻辑回归实现
# my_sklearn/linear_model/logistic_regression.py
# 包含逻辑回归模型的实现import numpy as npclass MyLogisticRegression:def __init__(self, learning_rate=0.01, epochs=1000):self.learning_rate = learning_rate # 学习率self.epochs = epochs # 迭代次数self.weights = None # 权重self.bias = None # 偏置# Sigmoid 激活函数def sigmoid(self, linear_output):result = 1 / (1 + np.exp(-linear_output))return result# 损失函数:交叉熵损失def compute_loss(self, X, y):m = len(y)predictions = self.sigmoid(np.dot(X, self.weights) + self.bias)loss = -1/m * np.sum(y * np.log(predictions) + (1 - y) * np.log(1 - predictions))return loss# 训练模型def fit(self, X, y):m, n = X.shapeself.weights = np.zeros(n)self.bias = 0for epoch in range(self.epochs):# 前向传播z = np.dot(X, self.weights) + self.bias # 计算线性组合predictions = self.sigmoid(z) # 通过sigmoid函数得到概率# 反向传播dw = (1/m) * np.dot(X.T, (predictions - y))db = (1/m) * np.sum(predictions - y)# 更新参数self.weights -= self.learning_rate * dwself.bias -= self.learning_rate * db# 每100次迭代输出一次损失if epoch % 100 == 0:loss = self.compute_loss(X, y)print(f"Epoch {epoch}: Loss = {loss}")# 预测def predict(self, X):z = np.dot(X, self.weights) + self.biaspredictions = self.sigmoid(z)class_predictions = np.where(predictions >= 0.5, 1, 0)return class_predictions
2. my_sklearn/metrics/accuracy.py — 自定义准确率计算
# my_sklearn/metrics/accuracy.pydef my_accuracy_score(y_true, y_pred):"""计算准确率:正确预测的样本数 / 总样本数参数:y_true -- 真实标签y_pred -- 预测标签返回:accuracy -- 准确率"""correct = sum(y_true == y_pred)total = len(y_true)accuracy = correct / totalreturn accuracy
3. my_sklearn/linear_model/__init__.py — 导出 MyLogisticRegression
# my_sklearn/linear_model/__init__.py
# linear_model子包初始化文件# 从logistic_regression模块导入类
from .logistic_regression import MyLogisticRegression# 导出的类列表
__all__ = ['MyLogisticRegression']
4. my_sklearn/metrics/__init__.py — 导出准确率函数
# my_sklearn/metrics/__init__.py
# metrics子包初始化文件# 从accuracy模块导入函数
from .accuracy import my_accuracy_score# 导出的函数列表
__all__ = ['my_accuracy_score']
5. my_sklearn/__init__.py — 主包初始化
# my_sklearn/__init__.py
# 主包初始化文件# 导入子模块,使它们可以通过my_sklearn.xxx直接访问
from . import metrics
from . import linear_model
6. main.py — 主程序文件,包含数据处理和模型对比
# main.pyimport numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression as SklearnLogisticRegression
from sklearn.metrics import accuracy_score # 导入sklearn的准确率计算函数# 导入自定义模块
from my_sklearn.linear_model import MyLogisticRegression # 导入自定义逻辑回归模型
from my_sklearn.metrics import my_accuracy_score # 导入自定义准确率计算函数# 1. 加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target# 只选择两类进行二分类
X = X[y != 2]
y = y[y != 2]# 2. 数据预处理(标准化)
scaler = StandardScaler()
X = scaler.fit_transform(X)# 3. 切分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 4. 使用自定义实现的逻辑回归
my_lr = MyLogisticRegression(learning_rate=0.01, epochs=1000)
my_lr.fit(X_train, y_train)# 5. 使用 sklearn 实现的逻辑回归
sklearn_lr = SklearnLogisticRegression(max_iter=1000)
sklearn_lr.fit(X_train, y_train)# 6. 对比自定义模型和 sklearn 模型的预测准确度
my_pred = my_lr.predict(X_test)
sklearn_pred = sklearn_lr.predict(X_test)# 使用自定义函数计算自定义模型的准确率
my_accuracy = my_accuracy_score(y_test, my_pred)
# 使用sklearn的函数计算sklearn模型的准确率
sklearn_accuracy = accuracy_score(y_test, sklearn_pred)print(f"My Logistic Regression Accuracy: {my_accuracy * 100:.2f}%")
print(f"Sklearn Logistic Regression Accuracy: {sklearn_accuracy * 100:.2f}%")
项目使用说明
-
安装依赖:
由于此项目只使用了numpy和sklearn库,你可以通过以下命令安装它们:pip install numpy scikit-learn -
运行项目:
运行main.py文件来加载数据集、训练模型并对比自定义模型和 sklearn 版本的准确度:python main.py
总结
这个项目实现了自定义的逻辑回归模型,并与 sklearn 的实现进行了对比。结构上,模仿了 sklearn 的模块化方式,将功能分为 linear_model 和 metrics 两个子模块。
相关文章:
从零构建逻辑回归: sklearn 与自定义实现对比
文章目录 理论基础1. 逻辑回归模型2. 损失函数3. 梯度推导(1) 计算 ∂ L ∂ y ^ \frac{\partial L}{\partial \hat{y}} ∂y^∂L(2) 计算 ∂ y ^ ∂ z \frac{\partial \hat{y}}{\partial z} ∂z∂y^(3) 计算 ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L(4) 计…...
1256:献给阿尔吉侬的花束--BFS多组输入--memset
1256:献给阿尔吉侬的花束--BFS多组输入--memset 题目 解析代码【结构体】用book标记且计步数的代码[非结构体法] 题目 解析 标准的BFS题目,在多组输入中要做的就是先找到这一组的起点和终点,然后将其传给bfs,在多组输入中最易忘记…...
【JavaEE】SpringBoot快速上手,探秘 Spring Boot,搭建 Java 项目的智慧脚手架
1.Spring Boot介绍 在学习SpringBoot之前, 我们先来认识⼀下Spring ,我们看下Spring官⽅的介绍 可以看到,Spring让Java程序更加快速, 简单和安全。 Spring对于速度、简单性和⽣产⼒的关注使其成为世界上最流⾏的Java框架。 Spring官⽅提供了很多开源的…...
【C】初阶数据结构9 -- 直接插入排序
前面我们学习了数据结构二叉树,接下来我们将开启一个新的章节,那就是在日常生活中经常会用到的排序算法。 所谓排序算法就是给你一堆数据,让你从小到大(或从大到小)的将这些数据排成一个有序的序列(这些数据…...
Lottie与LottieFiles:快速为前端Web开发注入精美动画的利器
目录 Lottie与LottieFiles:快速为前端Web开发注入精美动画的利器 一、Lottie是什么?从GIF到JSON的动画技术演进 1、传统动画臃肿的Gif 2、Lottie的突破性创新 二、Lottie的核心组件解析(Lottie的技术架构) 1、Lottie核心三要…...
Spring boot创建时常用的依赖
新建SpringBoot Maven项目中pom常用依赖配置及常用的依赖的介绍 1.springboot项目的总(父)依赖大全 <parent><artifactId>spring-boot-dependencies</artifactId><groupId>org.springframework.boot</groupId><version>2.3.3.RELEASE<…...
音乐API
https://neteasecloudmusicapi.vercel.app/docs/#/https://neteasecloudmusicapi.vercel.app/docs/#/ 使用实例 所有榜单内容摘要 说明 : 调用此接口,可获取所有榜单内容摘要 接口地址 : /toplist/detail 调用例子 : /toplist/detail 获取歌单所有歌曲 说明 : 由于网易云…...
UML(统一建模语言)详解:从理论到实践
1. UML概述 1.1 定义与历史背景 统一建模语言(Unified Modeling Language, UML) 是一种标准化的可视化建模语言,用于描述、设计、构造和文档化软件系统。它诞生于1994-1997年,由Grady Booch、James Rumbaugh和Ivar Jacobson&…...
C语言练习题--洛谷P5143攀爬者
题目背景 HKE 考完 GDOI 之后跟他的神犇小伙伴们一起去爬山。 题目描述 他在地形图上标记了 N 个点,每个点 Pi 都有一个坐标 (xi,yi,zi)。所有点对中,高度值 z 不会相等。HKE 准备从最低的点爬到最高的点,他的攀爬满足以下条件&am…...
MySQL常见字段值处理
一、数据拼接 1、CONCAT CONCAT(string1, string2, ..., stringN),将两个或多个字符串连接在一起 自动忽略 NULL 值参数,仅拼接非 NULL 的字符串。 第一个参数必须是分隔符(字符串)。 SELECT CONCAT(Hello, , World); -- 输…...
OpenCV实现图像分割与无缝合并
一、图像分割核心方法 1、阈值分割 #include <opencv2/opencv.hpp> using namespace cv; int main() {Mat img imread("input.jpg", IMREAD_GRAYSCALE);Mat binary;threshold(img, binary, 127, 255, THRESH_BINARY); // 固定阈值分割imwrite("binary.…...
百度之星2023——公园
这道题目用bfs做反而麻烦了。 首先抓题目关键字,要求“最少”,那大概率就是最短路径问题。虽然这题是一个无权图,用bfs也能求最短路径,但是我们知道使用dijkstra是能够利用dist数组持久化最短路径的,相比每次都要bfs&…...
从零搭建微服务项目Pro(第3-1章——本地/OSS图片文件存取)
前言: 在小型demo项目中,一般将图片音频等字节流文件存放本地数据库,但企业级项目中,由于数据量容量有限,需要借助OSS来管理大规模文件。 OSS(对象存储服务,Object Storage Service࿰…...
游戏引擎学习第147天
仓库:https://gitee.com/mrxiao_com/2d_game_3 上一集回顾 具体来说,我们通过隐式计算来解决问题,而不是像数字微分分析器那样逐步增加数据。我们已经涵盖了这个部分,并计划继续处理音量问题。不过,实际上我们现在不需要继续处理…...
Spring boot启动原理及相关组件
优质博文:IT-BLOG-CN 一、Spring Boot应用启动 一个Spring Boot应用的启动通常如下: SpringBootApplication Slf4j public class ApplicationMain {public static void main(String[] args) {ConfigurableApplicationContext ctx SpringApplication.…...
【Linux】信号处理以及补充知识
目录 一、信号被处理的时机: 1、理解: 2、内核态与用户态: 1、概念: 2、重谈地址空间: 3、处理时机: 补充知识: 1、sigaction: 2、函数重入: 3、volatile&…...
微服务——网关、网关登录校验、OpenFeign传递共享信息、Nacos共享配置以及热更新、动态路由
之前学习了Nacos,用于发现并注册、管理项目里所有的微服务,而OpenFeign简化微服务之间的通信,而为了使得前端可以使用微服务项目里的每一个微服务的接口,就应该将所有微服务的接口管理起来方便前端调用,所以有了网关。…...
【leetcode hot 100 19】删除链表的第N个节点
解法一:将ListNode放入ArrayList中,要删除的元素为num list.size()-n。如果num 0则将头节点删除;否则利用num-1个元素的next删除第num个元素。 /*** Definition for singly-linked list.* public class ListNode {* int val;* Lis…...
comctl32!ListView_OnSetItem函数分析LISTSUBITEM结构中的image表示图标位置
第一部分: BOOL ListView_SetSubItem(LV* plv, const LV_ITEM* plvi) { LISTSUBITEM lsi; BOOL fChanged FALSE; int i; int idpa; HDPA hdpa; if (plvi->mask & ~(LVIF_DI_SETITEM | LVIF_TEXT | LVIF_IMAGE | LVIF_STATE)) { …...
数据结构——多项式问题(顺序存储结构or链式存储结构)
补充:malloc函数: malloc 函数是 C 语言标准库中的一个重要函数,位于 <stdlib.h> 头文件中,主要用于在程序运行时动态分配内存。以下将详细介绍其用法。 前面的返回值指针可以自己定义,如 (int*&am…...
【学习方法】技术开发者的提问智慧:如何高效获得解答?
技术开发者的提问智慧:如何高效获得解答? 在技术开发过程中,每个人都会遇到无法解决的问题。此时,我们通常会向团队、社区或论坛求助。然而,为什么有些人的问题能迅速得到解答,而有些人的问题却石沉大海&a…...
记录小白使用 Cursor 开发第一个微信小程序(一):注册账号及下载工具(250308)
文章目录 记录小白使用 Cursor 开发第一个微信小程序(一):注册账号及下载工具(250308)一、微信小程序注册摘要1.1 注册流程要点 二、小程序发布流程三、下载工具 记录小白使用 Cursor 开发第一个微信小程序(…...
vue2项目修改浏览器显示的网页图标
1.准备一个新的图标文件,通常是. ico格式,也可以是. Png、. Svg等格式 2.将新的图标文件(例如:faviconAt.png)放入项目的public文件夹中。如下图 public文件夹中的所有文件都会在构建时原样复制到最终的输出目录(通常是dist) 3. 修改vue项目…...
spring boot3.4.3+MybatisPlus3.5.5+swagger-ui2.7.0
使用 MyBatis-Plus 操作 books 表。我们将实现以下功能: 创建实体类 Book。 创建 Mapper 接口 BookMapper。 创建 Service 层 BookService 和 BookServiceImpl。 创建 Controller 层 BookController。 配置 MyBatis-Plus 和数据库连接。 1. 项目结构 src ├─…...
【网络安全工程】任务10:三层交换机配置
CSDN 原创主页:不羁https://blog.csdn.net/2303_76492156?typeblog三层交换机是指在OSI(开放系统互连)模型中的第三层网络层提供路由功能的交换机。它不仅具备二层交换机的交换功能,还能实现路由功能,提供更为灵活的网…...
侯捷 C++ 课程学习笔记:C++内存管理机制
内存管理从平地到万丈高楼 内存管理入门(Memory Management 101) 需要具有动态分配并使用memory(存储(器),(计算机的)内存),使用过C标准库的容器࿰…...
JVM常用概念之本地内存跟踪
问题 Java应用启动或者运行过程中报“内存不足!”,我们该怎么办? 基础知识 对于一个在本地机器运行的JVM应用而言,需要足够的内存来存储机器代码、堆元数据、类元数据、内存分析等数据结构,来保证JVM应用的成功启动以及未来平…...
【鸿蒙开发】Hi3861学习笔记- 软件定时器示例
00. 目录 文章目录 00. 目录01. 定时器概述02. 定时器API03. 定时器常用API3.1 osTimerNew3.2 osTimerDelete3.3 osTimerStart3.4 osTimerStop 04. 程序示例05. 附录 01. 定时器概述 软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设…...
在Html5中仿Matlab自定义色带生成实践
目录 前言 一、RGB的相关知识 1、RGB的基本原理 2、RGB的数值表示 3、应用场景 二、ColorMap生成实战 1、外部库介绍 2、相关API 3、实例生成 三、总结 前言 在现代网页开发与数据可视化领域,色彩的表现力对于信息传达和视觉体验起着至关重要的作用。色带&…...
贪心算法--
1.柠檬水找零 link:860. 柠檬水找零 - 力扣(LeetCode) code class Solution { public:bool lemonadeChange(vector<int>& bills) {// 贪心算法, 优先花出大面额bill, 尽可能保护小面额billint five 0, ten 0;// 不…...
