LeetCode 2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版
【LetMeFly】2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版
文章目录
- 【LetMeFly】2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版
- 问题描述
- 解题方法:贪心
- 那行,我们先选赔钱的
- 到了能赚钱时候也不容易
- 解法来了
- 写法上的优化
- 时空复杂度分析
- AC代码(简化写法)
- C++
- Python
- Java
- Go
问题描述
力扣题目链接:https://leetcode.cn/problems/minimum-money-required-before-transactions/
给你一个下标从 0 开始的二维整数数组 transactions,其中transactions[i] = [costi, cashbacki] 。
数组描述了若干笔交易。其中每笔交易必须以 某种顺序 恰好完成一次。在任意一个时刻,你有一定数目的钱 money ,为了完成交易 i ,money >= costi 这个条件必须为真。执行交易后,你的钱数 money 变成 money - costi + cashbacki 。
请你返回 任意一种 交易顺序下,你都能完成所有交易的最少钱数 money 是多少。
示例 1:
输入:transactions = [[2,1],[5,0],[4,2]] 输出:10 解释: 刚开始 money = 10 ,交易可以以任意顺序进行。 可以证明如果 money < 10 ,那么某些交易无法进行。
示例 2:
输入:transactions = [[3,0],[0,3]] 输出:3 解释: - 如果交易执行的顺序是 [[3,0],[0,3]] ,完成所有交易需要的最少钱数是 3 。 - 如果交易执行的顺序是 [[0,3],[3,0]] ,完成所有交易需要的最少钱数是 0 。 所以,刚开始钱数为 3 ,任意顺序下交易都可以全部完成。
提示:
1 <= transactions.length <= 105transactions[i].length == 20 <= costi, cashbacki <= 109
解题方法:贪心
“在运气和实力面前,我选择了实力”——小T如是说。
不论机遇多么坏,我都必将不负债。
那么,最“坏”的机遇是什么?当然是先亏钱( c o s t < c a s n b a c k cost \lt casnback cost<casnback)再赚钱,主打一个完事开头难。
那行,我们先选赔钱的
对于两笔赔钱投资[[6, 4], [3, 2]],有两种选择方案:
- 先选
[6, 4],那么我们需要初始资金max(6, 6 + 3 - 4) = 5 = max(6, (6 - 4) + (3 - 2) + 2) - 先选
[3, 2],那么我们需要初始资金max(3, 3 + 6 - 2) = 7 = (3 - 2) + (6 - 4) + 4
有没有发现,不论选择方案如何,初始资金都为max(cost, 赔钱总额 + 最后一次投资的cashback)。
想要初始资金最大,那么我们就最后选“cashback”最大的那次投资。
赔钱投资的最大初始资金要求为赔钱总额 + max(cashback_赔),最终剩余max(cashback_赔)开始进行赚钱投资。
到了能赚钱时候也不容易
好了,现在开始赚钱投资,钱开始越来越多了。但是,能赚钱不等于容易赚钱。想要赚钱,你得有那个资本。
既然接下来每一笔都会赚钱,也就是说每经过一笔交易所需的负担就会减小一些,所以我们不如上来就选最难的那个。
上来就选cost最大的那个,所需金额为
max(cost_赚)。
别忘了,赔钱阶段虽然赔钱,但是最终我们还剩下了max(cashback_赔)。因此还需要资金max(0, max(cashback_赔) - max(cost_赚))。
解法来了
总结:两次遍历,第一次只遍历赔钱的交易,第二次遍历不赔钱的交易。
- 对于赔钱的交易,所需初始资金
ans = 赔钱总额 + max(cashback_赔) - 对于不赔钱交易,还需初始资金加上
max(0, max(cashback_赔) - max(cost_赚))
下面先贴一个完整版代码,再放一个核心代码。
完整版代码:
/** @Author: LetMeFly* @Date: 2025-01-25 08:08:05* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-01-25 09:53:23*/
#ifdef _WIN32
#include "_[1,2]toVector.h"
#endif/*
先选赔的[[6, 4], [3, 2]]:先[6, 4]的话需要初始资金max(6, 6+3-4)=max(6, 5)=6=max(6, (6-4)+(3-2)+2)先[3, 2]的话需要初始资金max(3, 6+3-2)=max(3, 7)=7=(3-2)+(6-4)+4对于赔的:初始资金:赔钱总额+最大cashback结束资金:最大cashback
后选不赔的赚的一样:[[1, 2], [2, 3]],先[2, 3]再[1, 2]赚的不同:[[3, 5], [7, 8]]:先[3, 5]的话需要初始资金7-(5-3)=5先[7, 8]的话需要初始资金7反正就是只要钱到了最大的“cost”,钱就够了。如果先投资“cost”比较小的话,一定会赚,本金加上赚的钱达到最大cost就行,所以初始值所需较小。
*/
typedef long long ll;class Solution {
public:ll minimumMoney(vector<vector<int>>& transactions) {ll ans = 0;int M_pei = 0;// 先算赔的for (vector<int>& transaction : transactions) {if (transaction[1] < transaction[0]) {ans += transaction[0] - transaction[1];M_pei = max(M_pei, transaction[1]);}}ans += M_pei;// 再算赚的,初始资金M_peiint M_zhuan = 0;for (vector<int>& transaction : transactions) {if (transaction[1] >= transaction[0]) {M_zhuan = max(M_zhuan, transaction[0]);}}ans += max(M_zhuan - M_pei, 0);return ans;}
};#ifdef _WIN32
/*
[[2,1],[5,0],[4,2]]10
*/
/*
[[36,79],[94,94],[12,54],[71,25],[34,78],[89,66],[66,25],[7,29],[5,58],[2,25],[10,83],[62,62],[11,52],[40,5],[10,79],[74,53],[33,90],[91,81],[30,84]]270
*/// 暴力验证一个答案是否正确,复杂度O(len(t)!),对于10以内的数据还算可行
bool isok_baoliYanzheng(vector<vector<int>>& t, ll init) {sort(t.begin(), t.end());auto isok = [](vector<vector<int>>& t, ll init) {for (vector<int>& t0 : t) {if (init < t0[0]) {return false;}init += t0[1] - t0[0];}return true;};do {for (vector<int>& t0 : t) {cout << '(' << t0[0] << ", " << t0[1] << "), ";}cout << endl;bool isThisOk = isok(t, init);if (!isThisOk) {return false;}} while (next_permutation(t.begin(), t.end()));return true;
}int main() {string s;Solution sol;while (cin >> s) {vector<vector<int>> v = stringToVectorVector(s);debug(v);ll ans = sol.minimumMoney(v);dbg(ans);if (v.size() <= 10) {cout << "ifOk: ";fflush(stdout);cout << isok_baoliYanzheng(v, ans) << endl;}}return 0;
}
#endif
核心代码:
ll ans = 0;
int M_pei = 0;
// 先算赔的
for (vector<int>& transaction : transactions) {if (transaction[1] < transaction[0]) {ans += transaction[0] - transaction[1];M_pei = max(M_pei, transaction[1]);}
}
ans += M_pei;
// 再算赚的,初始资金M_pei
int M_zhuan = 0;
for (vector<int>& transaction : transactions) {if (transaction[1] >= transaction[0]) {M_zhuan = max(M_zhuan, transaction[0]);}
}
ans += max(M_zhuan - M_pei, 0);
return ans;
写法上的优化
上述代码的伪代码为:
ans = 0
M_pei = 0
for 赔钱交易 {ans += 赔钱总额M_pei = max(cashback)
}
ans += M_pei
M_zhuan = 0
for 不赔钱交易 {M_zhuan = max(cost)
}
if M_zhuan > M_pei {ans += M_zhuan - M_pei
}
我们不妨调换个顺序:
ans = 0
M_pei = 0
for 赔钱交易 {ans += 赔钱总额M_pei = max(cashback)
}
M_zhuan = 0
for 不赔钱交易 {M_zhuan = max(cost)
}
ans += M_pei // 将这一行调换到这里
if M_zhuan > M_pei {ans += M_zhuan - M_pei
}
那么,最后4行的:
ans += M_pei
if M_zhuan > M_pei {ans += M_zhuan - M_pei
}
就可以简写为:
ans += max(M_zhuan, M_pei)
同时,前面10行的:
ans = 0
M_pei = 0
for 赔钱交易 {ans += 赔钱总额M_pei = max(cashback)
}
M_zhuan = 0
for 不赔钱交易 {M_zhuan = max(cost)
}
就可以缩减为一次遍历:
ans = 0
M_pei = 0
M_zhuan = 0
for 交易 {if cost > cashback { // 赔钱ans += 赔钱总额M_pei = max(cashback)} else {M_zhuan = max(cost)}
}
不难发现,如果赔钱则cashback更小,如果不赔钱则cost更小。也就是说M_pei和M_zhuan其实都是min(cost, cashback)的最大值。
因此上述代码还可以简写为:
ans = 0
M = 0
for 交易 {ans += max(0, cost - cashback)M = max(M, min(cost, cashback))
}
也就是说:
最终答案为:赔钱总额 + 最大的“min(cost, cashback)”
时空复杂度分析
- 时间复杂度 O ( l e n ( t r a n s a c t i o n s ) ) O(len(transactions)) O(len(transactions))
- 空间复杂度 O ( 1 ) O(1) O(1)
AC代码(简化写法)
C++
/** @Author: LetMeFly* @Date: 2025-01-25 09:58:52* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-01-25 09:59:57*/
typedef long long ll;class Solution {
public:ll minimumMoney(vector<vector<int>>& transactions) {ll ans = 0;int M = 0;for (vector<int>& t : transactions) {ans += max(0, t[0] - t[1]);M = max(M, min(t[0], t[1]));}return ans + M;}
};
Python
'''
Author: LetMeFly
Date: 2025-01-25 10:00:39
LastEditors: LetMeFly.xyz
LastEditTime: 2025-01-25 10:02:46
'''
from typing import Listclass Solution:def minimumMoney(self, transactions: List[List[int]]) -> int:return sum(max(0, c - e) for c, e in transactions) + max(min(t) for t in transactions)
Java
/** @Author: LetMeFly* @Date: 2025-01-25 10:05:00* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-01-25 10:06:21*/
class Solution {public long minimumMoney(int[][] transactions) {long ans = 0;int M = 0;for (int[] t : transactions) {ans += Math.max(0, t[0] - t[1]);M = Math.max(M, Math.min(t[0], t[1]));}return ans + M;}
}
Go
/** @Author: LetMeFly* @Date: 2025-01-25 10:07:19* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-01-25 10:12:39*/
package mainfunc max_MMRBT[T int](a T, b T) T {if a > b {return a}return b
}func min_MMRBT(a int, b int) int {if a < b {return a}return b
}func minimumMoney(transactions [][]int) (ans int64) {M := 0for _, t := range transactions {ans += int64(max_MMRBT(0, t[0] - t[1]))M = max_MMRBT(M, min_MMRBT(t[0], t[1]))}ans += int64(M)return
}
同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/145352577
相关文章:
LeetCode 2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版
【LetMeFly】2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版 文章目录 【LetMeFly】2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚…...
前端-Rollup
Rollup 是一个用于 JavaScript 的模块打包工具,它将小的代码片段编译成更大、更复杂的代码,例如库或应用程序。它使用 JavaScript 的 ES6 版本中包含的新标准化代码模块格式,而不是以前的 CommonJS 和 AMD 等特殊解决方案。ES 模块允许你自由…...
ubuntu黑屏问题解决
重启Ubuntu后,系统自动进入tty1,无法进入桌面。想到前几天安装了一些主题之类的,然后今天才重启,可能是这些主题造成冲突或者问题了把。 这里直接重新安装ubuntu-desktop解决: 更新源: sudo apt-get upd…...
MV结构下设置Qt表格的代理
目录 预备知识 模型 关联 刷新 示例 代理 模型 界面 结果 完整资料见: 所谓MV结构,是“model-view”(模型-视图)的简称。也就是说,表格的数据保存在model中,而视图由view实现。在我前面的很多博客…...
vue3相关知识点
title: vue_1 date: 2025-01-28 12:00:00 tags:- 前端 categories:- 前端vue3 Webpack ~ vite vue3是基于vite创建的 vite 更快一点 一些准备工作 准备后如图所示 插件 Main.ts // 引入createApp用于创建应用 import {createApp} from vue // 引入App根组件 import App f…...
Lustre v6 语法 - 时序表达式
概述 Lustre v6 语法中,与时序表达式有关的运算,包括 ->(followed by), pre(previous), fby, current, when, merge。其中,除 merge 运算是 Lustre v6 中新引入的外,其余在 Lustre Core 语法中已有定义。 与时序表达式有关的…...
vs2013 使用 eigen 库编译时报 C2059 错的解决方法
(个人感觉)vs2013 就不能使用版本大于等于 3.4 的 eigen,使用 3.3.9 就可以了,再不行就用 3.3.8 另一个博主也遇到过用 vs2013 的时候不能编译 3.4 的 eigen 的问题,不过我用的是 win11,所以感觉跟操作系统…...
Kafka 消费端反复 Rebalance: `Attempt to heartbeat failed since group is rebalancing`
文章目录 Kafka 消费端反复 Rebalance: Attempt to heartbeat failed since group is rebalancing1. Rebalance 过程概述2. 错误原因分析2.1 消费者组频繁加入或退出2.1.1 消费者故障导致频繁重启2.1.2. 消费者加入和退出导致的 Rebalance2.1.3 消费者心跳超时导致的 Rebalance…...
【第九天】零基础入门刷题Python-算法篇-数据结构与算法的介绍-六种常见的图论算法(持续更新)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、Python数据结构与算法的详细介绍1.Python中的常用的图论算法2. 图论算法3.详细的图论算法1)深度优先搜索(DFS)2…...
微服务网关鉴权之sa-token
目录 前言 项目描述 使用技术 项目结构 要点 实现 前期准备 依赖准备 统一依赖版本 模块依赖 配置文件准备 登录准备 网关配置token解析拦截器 网关集成sa-token 配置sa-token接口鉴权 配置satoken权限、角色获取 通用模块配置用户拦截器 api模块配置feign…...
shell脚本批量修改文件名之方法(The Method of Batch Modifying File Names in Shell Scripts)
shell脚本批量修改文件名方法 我们可以使用Shell脚本来实现这个功能。Shell脚本是一种用于自动化任务的编程语言,它可以在Unix/Linux操作系统上运行。在这个脚本中,我们将使用一个for循环来遍历目标目录下的所有文件,并使用mv命令将每个文件…...
华为小米vivo向上,苹果荣耀OPPO向下
日前,Counterpoint发布的手机销量月度报告显示,中国智能手机销量在2024年第四季度同比下降3.2%,成为2024年唯一出现同比下滑的季度。而对于各大智能手机品牌来说,他们的市场份额和格局也在悄然发生变化。 华为逆势向上 在2024年第…...
国产编辑器EverEdit - 输出窗口
1 输出窗口 1.1 应用场景 输出窗口可以显示用户执行某些操作的结果,主要包括: 查找类:查找全部,筛选等待操作,可以把查找结果打印到输出窗口中; 程序类:在执行外部程序时(如:命令窗…...
获取snmp oid的小方法1(随手记)
snmpwalk遍历设备的mib # snmpwalk -v <SNMP version> -c <community-id> <IP> . snmpwalk -v 2c -c test 192.168.100.201 .根据获取的值,找到某一个想要的值的oid # SNMPv2-MIB::sysName.0 STRING: test1 [rootzabbix01 fonts]# snmpwalk -v…...
DeepSeek模型:开启人工智能的新篇章
DeepSeek模型:开启人工智能的新篇章 在当今快速发展的技术浪潮中,人工智能(AI)已经成为了推动社会进步和创新的核心力量之一。而DeepSeek模型,作为AI领域的一颗璀璨明珠,正以其强大的功能和灵活的用法&…...
望获实时Linux系统:2024回顾与2025展望
2024年回顾 功能安全认证 2024年4月,望获操作系统V2获ISO26262:2018功能安全产品认证(ASIL B等级),达到国际功能安全标准。 EtherCAT实时性增强 2024年5月,发布通信实时增强组件,EtherCAT总线通信抖…...
2025_1_29 C语言学习中关于指针
1. 指针 指针就是存储的变量的地址,指针变量就是指针的变量。 1.1 空指针 当定义一个指针没有明确指向内容时,就可以将他设置为空指针 int* p NULL;这样对空指针的操作就会使程序崩溃而不会导致出现未定义行为,因为程序崩溃是宏观的&…...
SQL注入漏洞之高阶手法 宽字节注入以及编码解释 以及堆叠注入原理说明
目录 宽字节注入 编码区分 原理 函数 转译符号解释 注意 绕过方式详解 堆叠【Stack】注入攻击 注入语句 宽字节注入 在说宽字节注入之前 我们需要知道编码相关的知识点,这个有助于搞定什么是宽字节注入 分清楚是ascii码是什么宽字节注入代码里面加入了adds…...
doris:JSON
JSON 数据类型,用二进制格式高效存储 JSON 数据,通过 JSON 函数访问其内部字段。 默认支持 1048576 字节(1 MB),可调大到 2147483643 字节(2 GB),可通过 BE 配置string_type_length…...
ADC 精度 第一部分:精度与分辨率是否不同?
在与使用模数转换器(ADC)的系统设计师交谈时,我经常听到的一个最常见问题是: “你们的16位ADC也是16位准确的吗?” 这个问题的答案在于对分辨率和精度这两个概念的基本理解存在差异。尽管这是两个完全不同的概念&…...
生成模型:扩散模型(DDPM, DDIM, 条件生成)
扩散模型的理论较为复杂,论文公式与开源代码都难以理解。现有的教程大多侧重推导公式。为此,本文通过精简代码(约300行),更多以代码运行角度讲解扩散模型。 本代码包括扩散模型的主流技术复现: 1.DDPM (De…...
人格分裂(交互问答)-小白想懂Elasticsearch
通过交互式追问了解一个中间件 ? 啥是Elasticsearch ! 分布式搜索和分析引擎 ? 为啥是分布式搜索,单体难道用不了吗 ? 实际上是说这个东西可以分布式部署 ! 单机可用但扩展性差,分布式通过分片、副本和负载均衡实现海量数据存储与高并发处理 ? 提…...
【hot100】刷题记录(7)-除自身数组以外的乘积
题目描述: 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#x…...
鸢尾花书01---基本介绍和Jupyterlab的上手
文章目录 1.致谢和推荐2.py和.ipynb区别3.Jupyterlab的上手3.1入口3.2页面展示3.3相关键介绍3.4代码的运行3.5重命名3.6latex和markdown说明 1.致谢和推荐 这个系列是关于一套书籍,结合了python和数学,机器学习等等相关的理论,总结的7本书籍…...
可扩展架构:如何打造一个善变的柔性系统?
系统的构成:模块 + 关系 我们天天和系统打交道,但你有没想过系统到底是什么?在我看来,系统内部是有明确结构 的,它可以简化表达为: 系统 = 模块 + 关系 在这里,模块是系统的基本组成部分,它泛指子系统、应用、服务或功能模块。关系指模块 之间的依赖关系,简单…...
C++并发:C++内存模型和原子操作
C11引入了新的线程感知内存模型。内存模型精确定义了基础构建单元应当如何被运转。 1 内存模型基础 内存模型牵涉两个方面:基本结构和并发。 基本结构关系到整个程序在内存中的布局。 1.1 对象和内存区域 C的数据包括: 内建基本类型:int&…...
实验作业管理系统的设计与实现
标题:实验作业管理系统的设计与实现 内容:1.摘要 本系统旨在解决当前实验作业管理中存在的问题,提高管理效率和质量。通过对现有系统的调研和分析,我们确定了系统的功能需求和性能要求,并采用了先进的技术和架构进行设计和实现。系统实现了实…...
宝塔mysql数据库容量限制_宝塔数据库mysql-bin.000001占用磁盘空间过大
磁盘空间占用过多,排查后发现网站/www/wwwroot只占用7G,/www/server占用却高达8G,再深入排查发现/www/server/data目录下的mysql-bin.000001和mysql-bin.000002两个日志文件占去了1.5G空间。 百度后学到以下知识,做个记录。 mysql…...
2859.计算K置位下标对应元素的和
示例 1:输入:nums [5,10,1,5,2], k 1 输出:13 解释:下标的二进制表示是: 0 0002 1 0012 2 0102 3 0112 4 1002 下标 1、2 和 4 在其二进制表示中都存在 k 1 个置位。 因此,答案为 nums[1] nums[…...
8. 网络编程
网络的基本概念 TCP/IP协议概述 OSI和TCP/IP模型 socket(套接字) 创建socket 字节序 字节序转换函数 通用地址结构 因特网地址结构 IPV4地址族和字符地址间的转换(点分十进制->网络字节序) 填写IPV4地址族结构案例 掌握TCP协议网络基础编程 相关函数 …...
