Monday, November 21, 2016

LeetCode 465 － Optimal Account Balancing

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 and z > 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.

in the problem, construct an isolated system. It mean the total amount of money in the system keeps constant. Thus, what matters is the amount of extra money each person have after all transactions complete. For example, if id1 gave id2 5$, then after that transaction id1's money decreased to 5$, on the contrary id2's money increased to 5$. That way, we know how did change account of each person. For imagination let's consider the following input [[1,2,3],[2,3,5], [4,1,6]]:

Now, we have some negative account changes and positive account changes. By the way it is not hard to see that they compensate each other. Now, our task is to balance the accounts, by performing minimal amount of transactions. For instance we can balance these accounts, by performing the following transactions: [1,2,2], [3,4,5], [1,4,1]. After that, all accounts become balanced, i.e 0 extra money in total. But we have performed 3 transactions. Can we do better? May be. The number of transactions depend on the order of pairs taking part in each transaction. Consequently, the next question is, 'how to know which set of pairs give minimum number of transactions?'. One solution idea is just, brute force through all pairs and just take the minimum number of transactions. Another idea is just take some random combinations of pairs and take the minimum number of trans so far.

P.S: May be there are other elegant and exact solutions and this solution doesn't pretend to the best one, but it is quite reasonable. The more random shuffles you do, the more probability of hitting the answer. For that test cases 1000 is enough, may be less...

However, this missed the case that P pays N $x, where $x < p and $x < n.

For example, the first person of (2, 50, 50, ..., 50) could pay $1 to both the first and last person of (51, 50, 50, ..., 50, 51), and get the minimal number of transactions. (This may not be a good example, but you know what I mean.)

I considered only the cases when some of the pairs pays off to close others account. Now, question is what if a pair makes transaction with some x$, where x<p and x< n and achieve minimal amount of transactions? Intuitively, such kind of transaction cannot decrease the total amount of transactions. Because, it doesn't change the state of the isolated system (total money flow doesn't change). But i think it is provable too.

Yes, I see. Thank you for pointing out! But I think the reason is randomization, not that type of transactions you mentioned. My solution takes 1000 random permutations. But actually, it worth considering all permutations. So in that case the algorithm would run O(n!) time. After i increased the number of iterations up 100000, My solution started to churning out answers from 18 - 14. Therefore I decided to add some simple correction to perform obvious transactions first:

The code above first makes transactions where we can balance two accounts by one transaction. It means where n == p. So the rest of the accounts are balanced randomly. Now the code gives correct answers with higher probability.