【LetMeFly】2412.完成所有交易的初始最少钱数:【年度巨献】举例说明(讲明白),由难至简(手脚不乱),附Python一行版 问题描述 力扣题目链接: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 <= 105
transactions[i].length == 2
0 <= costi , cashbacki <= 109
解题方法:贪心
“在运气和实力面前,我选择了实力”——小T如是说。
不论机遇多么坏,我都必将不负债。
那么,最“坏”的机遇是什么?当然是先亏钱($cost \lt 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_赚))
下面先贴一个完整版代码,再放一个核心代码。
完整版代码:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 #ifdef _WIN32 #include "_[1,2]toVector.h" #endif 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; 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; } };#ifdef _WIN32 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
核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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;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;
写法上的优化 上述代码的伪代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 }
我们不妨调换个顺序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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行的:
1 2 3 4 ans += M_peiif M_zhuan > M_pei { ans += M_zhuan - M_pei }
就可以简写为:
1 ans += max (M_zhuan, M_pei)
同时,前面10行的:
1 2 3 4 5 6 7 8 9 10 ans = 0 M_pei = 0 for 赔钱交易 { ans += 赔钱总额 M_pei = max (cashback) } M_zhuan = 0 for 不赔钱交易 { M_zhuan = max (cost) }
就可以缩减为一次遍历:
1 2 3 4 5 6 7 8 9 10 11 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)
的最大值。
因此上述代码还可以简写为:
1 2 3 4 5 6 ans = 0 M = 0 for 交易 { ans += max (0 , cost - cashback) M = max (M, min (cost, cashback)) }
也就是说:
最终答案为:赔钱总额 + 最大的“min(cost, cashback)”
时空复杂度分析
时间复杂度$O(len(transactions))$
空间复杂度$O(1)$
AC代码(简化写法) C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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 1 2 3 4 5 6 7 8 9 10 11 ''' Author: LetMeFly Date: 2025-01-25 10:00:39 LastEditors: LetMeFly.xyz LastEditTime: 2025-01-25 10:02:46 ''' from typing import List class 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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 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 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 := 0 for _, 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