Skip to content

Interview Solver

FeaturesPricingHelp
Sign In
FeaturesPricingHelpSign In
  1. Interview Questions
  2. /
  3. Problems
  4. /
  5. Invalid Transactions

Invalid Transactions

Flag card transactions that are too large or that happen in two cities within an hour for the same person. A test of careful parsing and grouping before comparing. Solve it below in Python or JavaScript, then read the walkthrough.

Solve it in your browserRead the solution
MediumArrayHash TableStringSortingAsked at 75 companies incl. Google, Amazon, Microsoft

Problem

You're given a list of card transactions. Each one is a string "name,time,amount,city": the person's name, the time in minutes, the amount, and the city where it happened.

A transaction is suspicious if either of these is true:

  • its amount is greater than 1000, or
  • the same person made another transaction in a different city at most 60 minutes before or after it (the gap |t1 - t2| ≤ 60).

Both transactions in a too-close pair are suspicious. Return every suspicious transaction string, in any order. If the same string appears twice in the input and is suspicious, include it twice.

Example 1

Input
transactions = ["mia,10,300,paris", "mia,55,80,berlin"]
Output
["mia,10,300,paris", "mia,55,80,berlin"]

Mia paid in Paris and in Berlin 45 minutes apart, so both are suspicious.

Example 2

Input
transactions = ["tom,100,1500,cairo", "tom,400,20,cairo"]
Output
["tom,100,1500,cairo"]

The first is over 1000. The second is in the same city, so it is fine.

Example 3

Input
transactions = ["kai,0,50,quito", "lee,30,50,tokyo", "kai,61,50,tokyo"]
Output
[]

Kai's two payments are 61 minutes apart, one minute too far. Lee is a different person.

Constraints

  • 1 ≤ transactions.length ≤ 1000
  • Names and cities are 1 to 10 lowercase English letters.
  • 0 ≤ time ≤ 1000
  • 0 ≤ amount ≤ 2000

Practice

1
2
3
4

Runs 12 tests in your browser. Python loads on the first run (about 6 MB, then cached). Press ⌘/Ctrl + Enter to run.

Get asked Invalid Transactions in a real interview?

Interview Solver gives you a working solution live, during your actual coding interview. Invisible to screensharing.

Start Free Trial

How to solve Invalid Transactions

Pattern: Parse, group by key, compare within groups

The amount rule is a check on one record at a time. The city rule is the interesting one: it only ever compares transactions that share a name. So parse every string once into (name, time, amount, city, index), group by name, and only compare inside each group.

Track suspicion by index, not by string, so a transaction is reported once even if it fails both rules, and duplicate strings are each reported. With n at most 1000, comparing every pair inside a group is fast enough. If you want better, sort each group by time and only look at neighbours within the 60-minute window.

Approach 1: Every pair across the whole list

For each transaction, re-parse and compare it against every other one, checking name, city and time gap. Works, but re-parses strings on every comparison and wastes time on pairs with different names.

Time O(n²) · Space O(n)

Approach 2: Group by name, sort by time, scan the window

Group parsed records by name and sort each group by time. For each record, walk forward while the time gap is at most 60 and mark both when the cities differ. Fast when groups are large and spread out, but a window full of same-city records can still be quadratic.

Time O(n log n + pairs in window) · Space O(n)

Approach 3: Group by name, compare inside each group

  1. Parse each string once and keep its index.
  2. Mark index i if its amount is over 1000.
  3. Group indices by name. Inside each group, for every pair with different cities and a time gap of at most 60, mark both.
  4. Return the original strings for every marked index.

Simple, correct, and fast for the given limits.

Time O(n + Σ g²) for group sizes g, O(n²) worst case · Space O(n)

ApproachTimeSpace
Every pair across the whole listO(n²)O(n)
Group by name, sort by time, scan the windowO(n log n + pairs in window)O(n)
Group by name, compare inside each groupO(n + Σ g²) for group sizes g, O(n²) worst caseO(n)

Solution code

Try the practice editor first. Both solutions pass every test above.

▸Invalid Transactions solution in Python
from collections import defaultdict


def invalid_transactions(transactions: list[str]) -> list[str]:
    parsed = []
    for t in transactions:
        name, time, amount, city = t.split(",")
        parsed.append((name, int(time), int(amount), city))

    bad = [amount > 1000 for _, _, amount, _ in parsed]
    by_name = defaultdict(list)
    for i, (name, _, _, _) in enumerate(parsed):
        by_name[name].append(i)

    for group in by_name.values():
        for a in range(len(group)):
            i = group[a]
            for b in range(a + 1, len(group)):
                j = group[b]
                if parsed[i][3] != parsed[j][3] and abs(parsed[i][1] - parsed[j][1]) <= 60:
                    bad[i] = bad[j] = True

    return [t for t, flag in zip(transactions, bad) if flag]
▸Invalid Transactions solution in JavaScript
function invalidTransactions(transactions) {
  const parsed = transactions.map((t) => {
    const [name, time, amount, city] = t.split(',');
    return { name, time: Number(time), amount: Number(amount), city };
  });

  const bad = parsed.map((p) => p.amount > 1000);
  const byName = new Map();
  parsed.forEach((p, i) => {
    if (!byName.has(p.name)) byName.set(p.name, []);
    byName.get(p.name).push(i);
  });

  for (const group of byName.values()) {
    for (let a = 0; a < group.length; a++) {
      const i = group[a];
      for (let b = a + 1; b < group.length; b++) {
        const j = group[b];
        if (parsed[i].city !== parsed[j].city && Math.abs(parsed[i].time - parsed[j].time) <= 60) {
          bad[i] = bad[j] = true;
        }
      }
    }
  }

  return transactions.filter((_, i) => bad[i]);
}

Common mistakes

  • Using `< 60` instead of `≤ 60`. A gap of exactly 60 minutes counts.
  • Collecting results in a set of strings, which drops a duplicate transaction that should appear twice.
  • Adding a transaction twice when it fails both rules, or when it pairs with two different partners.
  • Comparing times as strings ("100" < "60" alphabetically). Convert to integers when parsing.
  • Only marking the later transaction of a too-close pair. Both are suspicious.

What interviewers look for

Clarify the rules before coding: is the window inclusive, are both members of a pair invalid, and should duplicates be reported twice. Interviewers use this problem to see whether you read requirements carefully, so asking is a plus.

Then structure the code: one parse step, one boolean array of "invalid" flags indexed by position, and a final pass that maps flags back to strings. Saying "I mark by index so each transaction is reported exactly once" shows you have thought about the double-counting trap.

Follow-up questions

How would you make the city check faster when one person has thousands of transactions?

Sort that person's records by time and use a sliding window of the last 60 minutes, keeping a count of records per city in the window. A record is invalid if the window holds any record from another city, which you can tell from the number of distinct cities in the window. Doing it in both directions (or marking partners as you go) gives O(g log g) per group.

What if transactions arrive as a live stream?

Keep, per person, a queue of their transactions from the last 60 minutes. When a new one arrives, drop expired entries, check the queue for other cities, and flag both sides. Memory stays proportional to recent activity, not history.

What if the input strings could contain malformed records?

Validate during parsing: four fields, numeric time and amount, non-empty name and city. Decide with the interviewer whether bad records are skipped, reported as invalid, or raise an error, and keep that logic in the parse step so the rule checks stay clean.

Companies that ask Invalid Transactions

Invalid Transactions is tagged by 75 companies in our interview dataset. The score shows how often it comes up at each company.

  • Sap Concur100%
  • Stripe89.7%
  • Wixcom87.3%
  • D2l84%
  • Airtasker84%
  • Alcon82%
  • Canva81%
  • ADP81%
  • GitLab79%
  • Bloomberg78.7%
  • Quantiphi77%
  • Dialpad76%
  • Iqvia75%
  • Wex75%
  • Clever73%
  • Fivetran73%
  • Ticketmaster73%
  • Motorola Solutions72%
  • Appier71%
  • Redfin70%
  • Aptiv69%
  • Springworks Therapeutics67%
  • Onit67%
  • Pinwheel66%

and 51 more.

Practice next

  • Group AnagramsMediumHash map keyed by a canonical form
  • Analyze User Website Visit PatternMediumGroup, enumerate triples, count with a set per user
  • Accounts MergeMediumUnion-find over shared keys
  • Top K Frequent ElementsMediumCount, then bucket by frequency

Get live help in the real interview

Working solutions in real time during your actual interview. Invisible to screensharing.

Start Free Trial

No credit card required

Interview Solver
  • Home
  • About
  • Pricing
  • Sign in
  • Contact
  • Blog
  • Companion
  • Mobile
  • Help Center
  • Developers
  • Use Cases
  • AI Interview Copilot
  • Coding Interview Copilot
  • AI Interview Assistant
  • Software Engineer
  • Product Manager
  • Misc
  • Privacy Policy
  • Terms and Conditions
  • Refund & Cancellation
  • Discord Community
  • Affiliate Program
  • Compare
  • All Comparisons
  • vs Final Round AI
  • vs UltraCode
  • vs Interview Coder
  • vs LockedIn AI
  • vs AI Apply
  • Free Tools
  • ATS Resume Checker
  • STAR Method Builder
  • Salary Lookup
  • Big O Cheat Sheet
  • Total Comp Calculator
  • View All →
  • Interview Questions
  • Google Questions
  • Amazon Questions
  • Microsoft Questions
  • Meta Questions
  • Apple Questions
  • TikTok Questions
  • View All →
© 2026 Interview Solver, Inc. All rights reserved.