A group of friends went on holiday and sometimes lent each other money. For example, Alice paid for Bill's lunch for $10. Then later Chris gave Alice $5 for a taxi ride. We can model each transaction as a tuple (x, y, z) which means person x gave person y $z. Assuming Alice, Bill, and Chris are person 0, 1, and 2 respectively (0, 1, 2 are the person's ID), the transactions can be represented as [[0, 1, 10], [2, 0, 5]]
.
Given a list of transactions between a group of people, return the minimum number of transactions required to settle the debt.
Note:
- A transaction will be given as a tuple (x, y, z). Note that
x ≠ y
andz > 0
. - Person's IDs may not be linear, e.g. we could have the persons 0, 1, 2 or we could also have the persons 0, 2, 6.
Example 1:
Input: [[0,1,10], [2,0,5]] Output: 2 Explanation: Person #0 gave person #1 $10. Person #2 gave person #0 $5. Two transactions are needed. One way to settle the debt is person #1 pays person #0 and #2 $5 each.
Example 2:
Input: [[0,1,10], [1,0,1], [1,2,5], [2,0,5]] Output: 1 Explanation: Person #0 gave person #1 $10. Person #1 gave person #0 $1. Person #1 gave person #2 $5. Person #2 gave person #0 $5. Therefore, person #1 only need to give person #0 $4, and all debt is settled.
思路:对交易而言,如果有n笔交易可以构成一个环,那么n笔交易可以简化为n-1笔。比如(a给b25元,b给c25元,c给a50元。那么这个环是3笔,可以简化为2笔,b给a25元以及c给a25元。注意,成环
还要求环的总和为0)所以如果形成一个环,交易就可以减少一笔。为了最小化交易数量,我们的目标就转化为最大化可以成环的个数。
步骤:1 计算出每一个人的净额。整数表示这个人要还多少钱,负数表示这个人可以收多少钱。用net数组来记录每一个人的净额。假设我们得到的数组为[25, -50, 40, 10, -40, -10, 25]
2 从net[0]开始进行bfs搜索。q中加入的起始值为(net[0], [0], 1) 所对应的我们想要搜索的值为cur(当前的sum值), path, start.
3 进入bfs,跳出条件为当cur==0, 因为我们希望环越小越好(这样形成的环可以最多),立刻break。如果cur不等于0, 进入构造下一步q中所保存的值。q.appendleft((cur+net[i], path+[i]. i+1))
当cur==0跳出之后,我们需要对res进行update(self.res += len(path)-1)。同时我们把已经成环的i要从net中删掉。net = [net[i] for i in range(len(net)) if i not in path] 然后把这个net返回到主函数
4 在主函数中当net为空list的时候,意味着我们已经遍历过所有net的值,这时候得到的self.res就是最终答案。
class Solution: def minTransfers(self, transactions: List[List[int]]) -> int: if not transactions or len(transactions) == 0: return 0 d = collections.defaultdict(int) for x, y, money in transactions: d[x] += money d[y] -= money net = [d[k] for k in d if d[k] != 0] # print(net) self.res = 0 while net: q = collections.deque() q.append((net[0], [0], 1)) net = self.bfs(net, q) # print(net) return self.res def bfs(self, net, q): while q: cur, path, start = q.pop() if not cur: break for i in range(start, len(net)): q.appendleft((cur + net[i], path+[i], i+1)) self.res += len(path)-1 path =set(path) net = [net[i] for i in range(len(net)) if i not in path] return net