It was late in the day, some would consider it evening, and I have already had five consecutive interviews in a row; this company offered no real respite from it all; some interviewers asked if I needed a break, but those questions tend to have only one “correct” answer. I was really tired. All that was left was an algorithm interview from a pair of interviewers.
They asked this simply framed problem:
Given a list of debts between pairs of people, minimize the number of transactions needed to clear all debts.
I ended up receiving an offer, but I did terribly in this interview. My initial instinct was that this was a graph problem, perhaps NP-Hard. My second instinct was that they would not ask an NP-hard question for a simple software engineering role. My mistake was that I assumed my interviewers understood the problem they were asking.
I befriended one of the interviewers later and learned this was what they had in mind:
I went home that day frustrated, and later analyzed this problem more deeply. This problem was decidedly NP-hard. It’s a fun problem, but inappropriate for a software engineering interview.
The observation and the reduction are correct. The greedy solution is not. Consider this counterexample after steps 1 and 2 above:
The optimal perfect groupings are drawn in blue and red
The correct solution is 4 transactions, where 6 would be paired with the two 3’s the 10 would be paired with the two 5’s. The greedy approach produces 5 transactions.
Each transaction can eliminate either 1 or 2 participants. The optimal solution maximizes the number of transactions that can eliminate 2 participants. Let’s call a perfect grouping as a group of participants who owe debts and are owed debts that can be paired together without remainder. Each perfect grouping of participants introduces a transaction that can eliminate 2 participants.
The optimal solution would find the two perfect groupings, ($10 | $5, $5) and ($3, $3 | $6). The greedy solution only ever finds everyone as one perfect grouping ($10 $3 $3 | $6 $5 $5).
To prove that this problem is NP-Hard, the well-known subset sum problem, which is NP-Complete, can be reduced to this problem, thus proving that the problem is at least as hard as subset sum. The subset sum problem is a decision problem, where, given a set of integers S and a target integer s, whether there is a non-empty subset of S that sums to s. This reduction will use the positive variant of the subset problem, where all elements of S and the target integer s are positive.
The subset sum problem reduction visualized
This is the reduction:
Through the above reduction, this problem can decide the subset sum problem, which means this problem is at least as hard as subset sum. This problem is NP-Hard. QED.
The solution is to maximize the number of perfect groupings to minimize the number of transactions, because each perfect grouping reduces the number of transactions needed to clear all debts by 1. When there are no strict subsets that are perfect matchings, the entire solution becomes a single perfect grouping. Rephrased, the solution is to maximize the number of distinct subsets that sum to 0.
Stepping through the above counterexample to the greedy solution. Invalid states are not drawn in this visualization (there are 60 undrawn states).
This is the solution I found:
Run time analysis: At each state, there needs 2^k operations, where k is the number of unsettled participants debts to consider. There are (n choose k) states for a given k. Precompute all possible sums and store them into a lookup table O(2^n). Using the precomputed lookup table, there are O(2^k) operations per state, the big O runtime of this algorithm is:
A good explanation of why the two sides are equal can be found here. This algorithm will take O(2^n) space as there are O(2^n) states and O(2^n) sums.
The most frustrating part about all of this was that my interviewers thought that the problem was way easier than it actually is, and reported that I was not able to solve such an easy problem in the span of 45 minutes. This specific interview significantly hurt the offer I received. Unfortunately, there’s a lot of luck to the interview process as there is a lot of luck in life. The best things to do are to learn to not assume that the interviewers fully understand their own questions, and write a blog post about it.
Thank you Daniel Wasserman for helping me look over this article!