Fractional Share Inventory Trading
Problem
Problem Overview
Robinhood supports fractional share trading. Instead of sending every fractional order directly to the exchange, Robinhood can keep a small internal inventory of fractional shares for each stock symbol.
This is usually asked as a two-part simulation problem:
- First, process buy and sell orders and return Robinhood's final fractional inventory.
- Then, print the actual transactions Robinhood performs with users and the exchange.
The core data structure is a hash map from stock symbol to the fractional inventory currently held for that symbol. The main implementation detail is to avoid floating-point arithmetic. Store every share quantity as an integer number of hundredths, so 0.50 shares is stored as 50 and 1.00 share is stored as 100.
Part 1: Update Fractional Inventory
Problem Statement
You are given Robinhood's current fractional inventory and a list of user orders.
Inventory entries are strings in this format:
<symbol>/<quantity>
Order entries are strings in this format:
<side>/<symbol>/<quantity>
where:
BUYmeans the user buys shares from Robinhood.SELLmeans the user sells shares to Robinhood.quantityis a decimal share quantity with two digits of precision.
Rules:
- Robinhood only keeps fractional inventory internally.
- When a user buys shares, Robinhood first uses existing inventory.
- If inventory is not enough, Robinhood buys the minimum whole number of shares from the exchange needed to fill the order, then keeps any remainder as inventory.
- When a user sells shares, Robinhood adds those shares to inventory.
- Whenever inventory reaches at least
1.00share, Robinhood sells the whole-share portion to the exchange and keeps only the fractional remainder. - Return final non-zero inventory entries sorted by symbol in the same
<symbol>/<quantity>format.
Example
inventory = ["AAPL/0.60"]
orders = [
"SELL/AAPL/0.50",
"BUY/AAPL/0.70",
"BUY/TSLA/0.40",
]
Step-by-step:
Initial AAPL inventory = 0.60
User sells 0.50 AAPL:
inventory becomes 1.10
sell 1.00 whole share to the exchange
remaining AAPL inventory = 0.10
User buys 0.70 AAPL:
inventory has only 0.10
buy 1.00 share from the exchange
sell 0.70 to the user
remaining AAPL inventory = 0.40
User buys 0.40 TSLA:
inventory has 0.00
buy 1.00 share from the exchange
sell 0.40 to the user
remaining TSLA inventory = 0.60
Output:
["AAPL/0.40", "TSLA/0.60"]
Complexity
Let N be the number of inventory entries, M be the number of orders, and K be the number of stock symbols tracked.
- Time: O(N + M + K log K)
- Space: O(K)
The K log K term is only for sorted output. The order simulation itself is O(N + M).
Part 2: Print Each Transaction
Follow-Up Prompt
The interviewer may then ask:
"Can you also print each transaction Robinhood executes?"
For example, if a user sells 0.50 shares while Robinhood already has 0.60 shares of that stock in inventory, Robinhood should print two transactions:
BUY 0.50 from the user
SELL 1.00 to the exchange
The final inventory is 0.10.
Key Insight
The inventory update rules do not change. The follow-up adds an audit log of Robinhood's actions:
- User
BUY: Robinhood may first buy whole shares from the exchange, then sells the requested quantity to the user. - User
SELL: Robinhood buys the requested quantity from the user, then sells any whole-share inventory to the exchange.
Keep the log from Robinhood's perspective. A user sell is a Robinhood buy from the user. A user buy is a Robinhood sell to the user.
Example
inventory = ["AAPL/0.60"]
orders = [
"SELL/AAPL/0.50",
"BUY/AAPL/0.70",
"BUY/TSLA/0.40",
]
final_inventory, trades = process_fractional_orders_with_trades(
inventory,
orders,
)
Output:
final_inventory == ["AAPL/0.40", "TSLA/0.60"]
trades == [
"BUY/AAPL/0.50/USER",
"SELL/AAPL/1.00/EXCHANGE",
"BUY/AAPL/1.00/EXCHANGE",
"SELL/AAPL/0.70/USER",
"BUY/TSLA/1.00/EXCHANGE",
"SELL/TSLA/0.40/USER",
]
Complexity
Let T be the number of generated transactions.
- Time: O(N + M + T + K log K)
- Space: O(K + T)
Each order generates at most two transactions in this model, so T is O(M).
Why This Works
For each stock symbol, the only state that matters for future orders is the fractional remainder currently held by Robinhood.
When a user buys, any shortage can be covered by buying whole shares from the exchange. Buying the ceiling of shortage / 1.00 shares is the minimum whole-share exchange order that can fill the user's fractional buy.
When a user sells, Robinhood's inventory increases. Any whole-share portion can be immediately sold to the exchange, leaving only inventory % 1.00 as the fractional inventory.
Because each order only touches one symbol and all updates are constant-time arithmetic, a hash map is enough.
Common Variants
Quantities Already Multiplied By 100
Some versions avoid decimals entirely and give quantities as integers:
AAPL/60
SELL/AAPL/50
In that case, parse_quantity() should return int(raw) directly, and format_quantity() should still divide by 100 for display if formatted output is required.
Different String Layout
Several reported versions pass each inventory and order element as a string with fields separated by /, but the order of fields may differ. Keep parsing isolated in helper functions so the simulation logic does not change.
Preserve Input Symbol Order
If the interviewer wants output in first-seen symbol order instead of sorted order, maintain a separate symbols list when parsing inventory and orders. The update rules stay the same.
Print From The User Perspective
The follow-up can ask for logs from the user's perspective instead of Robinhood's perspective. Clarify this before coding. The same events are emitted, but the trade sides are inverted for user-facing logs.
Solution
Sign in to get AI feedback on your answer. Your work is saved while you do.
Sign in to evaluate