BNPL Transaction Settlement
A financial company provides customers a way to buy something now and pay for it later (BNPL) by issuing them loans. However, the logistics require moving money between multiple parties—customers, merchants, the company, and third-party entities—to ensure everyone is paid correctly upfront.
Given a list of pending transactions and the current end-of-day bank account balances, determine the updated balance for each party after applying all transactions.
A transaction [sender, receiver, amount] indicates that sender pays amount to receiver.
The final output should be a list of integers representing the balances of all unique parties mentioned in either transactions or initialBalance, sorted alphabetically by the party's name.
Example 1
Input
transactions = [["Alice","Bob","50"],["Bob","Charlie","30"],["Charlie","Alice","20"],["Alice","David","70"]], initialBalance = [["Alice","100"],["Bob","50"],["Charlie","75"],["David","25"]]Output
[0, 70, 85, 95]Explanation
1. Identify all unique parties: Alice, Bob, Charlie, David. 2. Apply transactions: - Alice: Starts with 100. Pays 50 to Bob, pays 70 to David, receives 20 from Charlie. Final: 100 - 50 - 70 + 20 = 0. - Bob: Starts with 50. Receives 50 from Alice, pays 30 to Charlie. Final: 50 + 50 - 30 = 70. - Charlie: Starts with 75. Receives 30 from Bob, pays 20 to Alice. Final: 75 + 30 - 20 = 85. - David: Starts with 25. Receives 70 from Alice. Final: 25 + 70 = 95. 3. Sort parties alphabetically: Alice (0), Bob (70), Charlie (85), David (95).
Example 2
Input
transactions = [["Alice","Bob","300"], ...], initialBalance = [["Alice","1000"], ..., ["Jack","400"]]Output
[750, 800, 50, 950, 550, 350, 350, 300, 300, 400]
Example 3
Input
transactions = [["Alice","Bob","150"], ...], initialBalance = [["Alice","500"], ...]Output
[500, 350, -50, 50, 550]
Constraints
- Initial balances and transaction amounts are integers provided as strings.
1 <= transactions.length <= 10⁴1 <= initialBalance.length <= 10⁴- Party names consist of alphanumeric characters.
- Amounts are positive integers.
BNPL Transaction Settlement
Overview
The goal is to calculate the final bank balances for a set of parties after a series of transactions are processed. We are given their starting balances and a list of transfers where money moves from a sender to a receiver.
The core logic involves:
- Tracking State: Maintaining a mapping of each unique person to their current net balance.
- Processing Updates: For every transaction, subtracting the amount from the sender and adding it to the receiver.
- Ordering: The final output must be ordered alphabetically by the party name, but return only the integer balances.
Brute Force
In a brute force approach, we might treat the input lists literally and perform repetitive searches. For every transaction, we could iterate through the entire list of parties to find the sender and receiver to update their values. However, since we need to handle parties that might appear in transactions but not in initialBalance (and vice versa), we first collect all unique names to build our ledger.
def settle_transactions(transactions: list[list[str]], initialBalance: list[list[str]]) -> list[int]:
# Collect all unique party names
parties = set()
for name, _ in initialBalance:
parties.add(name)
for sender, receiver, _ in transactions:
parties.add(sender)
parties.add(receiver)
# Sort names to ensure alphabetical order for the final output
sorted_names = sorted(list(parties))
# Initialize balances in a list corresponding to sorted_names
balances = [0] * len(sorted_names)
# Fill initial balances
for name, amt in initialBalance:
idx = sorted_names.index(name)
balances[idx] = int(amt)
# Process transactions by finding indices repeatedly
for sender, receiver, amt in transactions:
amount = int(amt)
s_idx = sorted_names.index(sender)
r_idx = sorted_names.index(receiver)
balances[s_idx] -= amount
balances[r_idx] += amount
return balances
Time complexity: O(N * M) — Where N is the number of unique parties and M is the number of transactions, due to the repeated use of .index() which performs a linear search.
Space complexity: O(N) — We store the unique party names and their balances.
Optimal / Best Approach
The optimal approach uses a Hash Map (Dictionary) to achieve O(1) lookups for each party. Instead of searching through a list to find a party's index, we map the name directly to their current balance.
- Initialize Ledger: Create a dictionary where keys are party names and values are integers. Populated this first with the
initialBalancedata. - Handle New Parties: Ensure that any party mentioned in
transactionswho wasn't ininitialBalanceis added to the dictionary with a starting balance of 0. - Process Transactions: Iterate through
transactionsonce. For each[sender, receiver, amount], update the dictionary values:ledger[sender] -= amountandledger[receiver] += amount. - Extract and Sort: Extract the keys (names), sort them alphabetically, and build the final list of balances based on that sorted order.
def settle_transactions(transactions: list[list[str]], initialBalance: list[list[str]]) -> list[int]:
# Use a dictionary for O(1) balance updates
ledger = {}
# Load initial balances
for name, balance_str in initialBalance:
ledger[name] = int(balance_str)
# Process transactions
for sender, receiver, amount_str in transactions:
amount = int(amount_str)
# Ensure parties exist in ledger (even if they had no initial balance)
if sender not in ledger:
ledger[sender] = 0
if receiver not in ledger:
ledger[receiver] = 0
ledger[sender] -= amount
ledger[receiver] += amount
# Sort the party names alphabetically
sorted_party_names = sorted(ledger.keys())
# Return balances in the sorted order of names
return [ledger[name] for name in sorted_party_names]
Time complexity: O(B + T + N log N) — Where B is the size of initialBalance, T is the number of transactions, and N is the number of unique parties (due to sorting). Space complexity: O(N) — We store the balance of each unique party in a hash map.
Edge Cases
- Zero Balance Parties: A party might exist in the initial list but never participate in a transaction. They must still appear in the final output.
- New Parties: A party might not have an initial balance but appears in a transaction. The logic handles this by initializing them to 0.
- Negative Balances: As seen in Example 3, it is possible for a party to spend more than their initial balance, resulting in a negative integer. The problem constraints allow for this.
- Large Integers: The amounts are provided as strings; using Python's
int()handles arbitrarily large integers automatically.
Fast
Comments on the solution
No comments on the solution yet. Start a thread about the editorial or your own approach.
No comments yet for BNPL Transaction Settlement. Be the first to start the thread.
No submissions recorded for this problem yet. Use Submit in the editor — each judge run is stored here.
Output
Input
Expected
Your output
Run to see your output.