Compute currency conversions with graph algorithms
Company: Stripe
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Onsite
Quick Answer: Stripe software-engineer onsite coding question: design data structures and algorithms to compute currency conversions from pairwise exchange rates. It tests modeling currencies as a weighted directed graph, chaining rates with BFS/DFS to answer queries (or -1 when unknown), supporting online updates and many queries efficiently, detecting contradictions and arbitrage in cycles, and computing all rates against a base via topological sort on a DAG, with time and space complexity analysis.
Constraints
- Each rate is given as [src, dst, r] with r > 0, meaning 1 src = r dst.
- 1 <= number of currencies (V) <= 10^3.
- Currency symbols are non-empty strings.
- A query for an unknown currency, or between two currencies with no connecting path, returns -1.0.
- A query [X, X] for a known currency X returns 1.0; for an unknown X it returns -1.0.
- Inputs are assumed consistent (no contradictory cycles); any path between two currencies yields the same rate.
Examples
Input: ([['A', 'B', 1.5], ['B', 'C', 1.5]], [['A', 'C'], ['A', 'B'], ['C', 'A'], ['A', 'X']])
Expected Output: [2.25, 1.5, 0.4444444444444444, -1.0]
Explanation: A:C chains 1.5 * 1.5 = 2.25; A:B is the direct rate 1.5; C:A is the reciprocal 1/2.25 = 0.4444...; X is an unknown currency so A:X returns -1.0.
Input: ([['USD', 'EUR', 0.9], ['EUR', 'GBP', 0.85]], [['USD', 'GBP'], ['GBP', 'USD'], ['USD', 'USD']])
Expected Output: [0.765, 1.307189542483661, 1.0]
Explanation: USD:GBP = 0.9 * 0.85 = 0.765; GBP:USD is the reciprocal 1/0.765 = 1.30718...; USD:USD is the identity 1.0.
Input: ([], [['A', 'B']])
Expected Output: [-1.0]
Explanation: No rates were ingested, so neither A nor B exists in the graph and the query returns -1.0.
Input: ([['A', 'B', 2.0]], [['A', 'C'], ['C', 'A'], ['A', 'A']])
Expected Output: [-1.0, -1.0, 1.0]
Explanation: C is an unknown currency, so both A:C and C:A return -1.0. A:A is the identity 1.0 because A is a known currency.
Input: ([['X', 'Y', 4.0], ['Y', 'Z', 0.25]], [['X', 'Z'], ['Z', 'X']])
Expected Output: [1.0, 1.0]
Explanation: X:Z = 4.0 * 0.25 = 1.0, a consistent chain; Z:X is the reciprocal 1/1.0 = 1.0, confirming the cycle multiplies back to 1.
Hints
- Model currencies as nodes and each rate A:B=1:r as a directed edge A->B with weight r. Always add the reciprocal edge B->A with weight 1/r so conversions work both directions.
- The implied rate of a path is the PRODUCT of its edge weights, not the sum. Carry an accumulated product as you traverse.
- Run a BFS or DFS from the query's source, accumulating the product; return the accumulator the moment you reach the destination.
- Handle the edge cases first: if either currency was never seen, return -1.0; if source equals destination (and is known), return 1.0; if the search exhausts with no path, return -1.0.