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.

LeetCode Problem 1555

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 sender
  • paid_to, the receiver
  • amount, 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_id
  • user_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 Transactions table 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 0 credit, 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

  1. Start with the Transactions table 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"
  1. 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.