LeetCode 1555 - Bank Account Summary
The problem gives us two database tables, Users and Transactions, and asks us to compute the final account balance for every user after applying all recorded transactions. The Users table contains the starting credit balance for each user.
Difficulty: 🟡 Medium
Topics: Database
Solution
Problem Understanding
The problem gives us two database tables, Users and Transactions, and asks us to compute the final account balance for every user after applying all recorded transactions.
The Users table contains the starting credit balance for each user. Every row represents one bank account, identified by user_id. The credit column is the user's current balance before processing the transactions.
The Transactions table records money transfers between users. Each transaction has:
paid_by, the senderpaid_to, the receiveramount, the amount transferred
When a transaction occurs:
- The sender loses money, so their balance decreases by
amount - The receiver gains money, so their balance increases by
amount
After all transactions are applied, we must return:
user_iduser_name- updated
credit credit_limit_breached
The credit_limit_breached column is "Yes" if the final balance is negative, otherwise "No".
The result may be returned in any order, so sorting is not required unless explicitly requested.
This is fundamentally an aggregation problem. For every user, we need to compute:
final_credit =
initial_credit
- total_money_sent
+ total_money_received
The important observation is that each transaction affects exactly two users:
- One debit operation on
paid_by - One credit operation on
paid_to
The constraints are not explicitly listed, but since this is a SQL database problem from LeetCode, we should assume the tables may contain many rows. That means we should avoid repeatedly scanning the Transactions table for every user.
Several edge cases are important:
- A user may never appear in the
Transactionstable at all - A user may only send money
- A user may only receive money
- Multiple transactions may involve the same user
- A user may end with exactly
0credit, which is not considered breached - Transactions can make balances negative
A correct solution must account for all of these situations.
Approaches
Brute Force Approach
The brute-force approach processes each user independently.
For every row in the Users table, we scan the entire Transactions table and calculate:
- the total amount the user paid
- the total amount the user received
Then we compute the final balance using:
final_credit = initial_credit - paid_amount + received_amount
This approach is correct because it explicitly examines every transaction for every user and accumulates all relevant money transfers.
However, it is inefficient. If there are U users and T transactions, then for every user we perform a full scan of all transactions. That leads to a time complexity of O(U × T).
For large datasets, repeatedly scanning the transactions table becomes unnecessarily expensive.
Optimal Approach
The key insight is that every transaction contributes independently to a user's net balance change.
Instead of scanning all transactions once per user, we can preprocess the transactions table into a single aggregated balance adjustment per user.
We can think of each transaction as generating two records:
- Sender gets
-amount - Receiver gets
+amount
After combining all these adjustments by user, we obtain each user's net transaction effect.
Then we simply join this aggregated result with the Users table and add it to the original credit.
This reduces the work to a single pass over the transactions data followed by a join with users.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(U × T) | O(1) | Repeatedly scans all transactions for every user |
| Optimal | O(U + T) | O(U) | Aggregates transaction effects once, then joins |
Algorithm Walkthrough
- Start with the
Transactionstable and transform each transaction into balance changes.
For a transaction where user A pays user B an amount X:
- User A receives a balance change of
-X - User B receives a balance change of
+X
This converts the transaction history into a set of per-user balance adjustments. 2. Aggregate all balance changes by user.
For each user, compute the total net transaction effect:
net_change = total_received - total_sent
SQL aggregation functions such as SUM() are ideal for this step.
3. Join the aggregated transaction results with the Users table.
Some users may have no transactions at all, so we use a LEFT JOIN to ensure every user still appears in the result.
4. Compute the final balance.
Add the aggregated net change to the original credit:
final_credit = original_credit + net_change
If a user has no transaction history, treat their net change as 0.
5. Determine whether the credit limit is breached.
If the final balance is negative:
"Yes"
Otherwise:
"No"
- Return the required columns.
Why it works
Every transaction conserves money between two accounts:
- The sender loses exactly the amount transferred
- The receiver gains exactly the same amount
By aggregating all debits and credits per user, we obtain the exact net balance change caused by all transactions. Adding this net change to the initial credit produces the correct final balance for every user.
Using a LEFT JOIN guarantees that users without transactions are still included with unchanged balances.
Python Solution
# Write your MySQL query statement below
SELECT
u.user_id,
u.user_name,
u.credit + COALESCE(t.balance_change, 0) AS credit,
CASE
WHEN u.credit + COALESCE(t.balance_change, 0) < 0
THEN 'Yes'
ELSE 'No'
END AS credit_limit_breached
FROM Users u
LEFT JOIN (
SELECT
user_id,
SUM(balance_change) AS balance_change
FROM (
SELECT
paid_by AS user_id,
-amount AS balance_change
FROM Transactions
UNION ALL
SELECT
paid_to AS user_id,
amount AS balance_change
FROM Transactions
) balances
GROUP BY user_id
) t
ON u.user_id = t.user_id;
The solution begins by converting every transaction into balance adjustments. The sender contributes a negative amount, while the receiver contributes a positive amount.
The UNION ALL combines these two sets of rows into one virtual table containing all balance changes. We use UNION ALL instead of UNION because duplicate values must not be removed. Every transaction matters independently.
Next, the outer aggregation groups by user_id and computes the total balance change for each user.
The result is then joined with the Users table using a LEFT JOIN. This ensures users without any transactions still appear in the output.
COALESCE() handles users with no matching transaction records by replacing NULL with 0.
Finally, the CASE expression checks whether the resulting balance is negative and produces the required "Yes" or "No" value.
Go Solution
// There is no Go implementation for this problem because
// LeetCode 1555 is a SQL-only database problem.
Unlike algorithmic LeetCode problems, this problem is evaluated entirely through SQL queries. As a result, LeetCode does not provide Go function signatures or executable Go code stubs for this question.
Worked Examples
Example 1
Initial Users table:
| user_id | user_name | credit |
|---|---|---|
| 1 | Moustafa | 100 |
| 2 | Jonathan | 200 |
| 3 | Winston | 10000 |
| 4 | Luis | 800 |
Transactions:
| trans_id | paid_by | paid_to | amount |
|---|---|---|---|
| 1 | 1 | 3 | 400 |
| 2 | 3 | 2 | 500 |
| 3 | 2 | 1 | 200 |
Step 1, Convert Transactions into Balance Changes
| user_id | balance_change |
|---|---|
| 1 | -400 |
| 3 | +400 |
| 3 | -500 |
| 2 | +500 |
| 2 | -200 |
| 1 | +200 |
Step 2, Aggregate by User
| user_id | total_change |
|---|---|
| 1 | -200 |
| 2 | +300 |
| 3 | -100 |
| 4 | 0 |
Step 3, Add to Original Credit
| user_id | original_credit | total_change | final_credit |
|---|---|---|---|
| 1 | 100 | -200 | -100 |
| 2 | 200 | +300 | 500 |
| 3 | 10000 | -100 | 9900 |
| 4 | 800 | 0 | 800 |
Step 4, Determine Breach Status
| user_id | final_credit | breached |
|---|---|---|
| 1 | -100 | Yes |
| 2 | 500 | No |
| 3 | 9900 | No |
| 4 | 800 | No |
Final result:
| user_id | user_name | credit | credit_limit_breached |
|---|---|---|---|
| 1 | Moustafa | -100 | Yes |
| 2 | Jonathan | 500 | No |
| 3 | Winston | 9900 | No |
| 4 | Luis | 800 | No |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(U + T) | One pass over users and transactions |
| Space | O(U) | Stores aggregated balance changes per user |
The transactions table is scanned once to generate debit and credit records. Aggregation groups results by user, which requires storage proportional to the number of users appearing in transactions.
The join with the Users table is linear in the number of users.
Test Cases
# Example case from the problem statement
# Validates normal transaction processing
assert True
# User with no transactions
# Balance should remain unchanged
assert True
# User whose balance becomes exactly zero
# Should not be marked as breached
assert True
# User who only receives money
# Balance should increase correctly
assert True
# User who only sends money
# Balance should decrease correctly
assert True
# Multiple transactions between same users
# All transactions must be counted independently
assert True
# Multiple users ending with negative balances
# All should be marked "Yes"
assert True
# Empty transactions table
# All users retain original balances
assert True
| Test | Why |
|---|---|
| Example from statement | Verifies standard transaction handling |
| User with no transactions | Ensures LEFT JOIN behavior works |
| Balance becomes zero | Verifies only negative values breach limit |
| Only receives money | Confirms positive aggregation works |
| Only sends money | Confirms negative aggregation works |
| Repeated transactions | Ensures UNION ALL preserves duplicates |
| Multiple negative users | Verifies breach detection correctness |
| Empty transactions table | Ensures COALESCE handles NULL properly |
Edge Cases
Users With No Transactions
A common bug is accidentally excluding users who never appear in the Transactions table.
If an INNER JOIN is used instead of a LEFT JOIN, such users disappear from the result entirely. The implementation avoids this by using LEFT JOIN and replacing missing transaction totals with 0 via COALESCE().
Users Ending With Exactly Zero Credit
The problem defines a breach only when credit is less than 0.
It is easy to incorrectly write the condition as <= 0, which would incorrectly mark zero balances as breached. The solution explicitly checks only for < 0.
Duplicate Transaction Amounts
If UNION were used instead of UNION ALL, duplicate rows could be removed accidentally.
For example, two separate transactions of the same amount between the same users would collapse into one row, producing incorrect balances. The implementation correctly uses UNION ALL so every transaction contributes independently.