Implement Card Validation and Recovery System
Company: Stripe
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Take-home Project
Quick Answer: This question evaluates algorithmic problem-solving and implementation skills in string processing, checksum validation (Luhn), pattern matching, combinatorics for counting masked completions, and single-error recovery for payment-card numbers.
Part 1: Basic VISA Validation Using the Luhn Checksum
Constraints
- 0 <= len(card_number) <= 32
- card_number may contain digits or other characters
- A valid VISA number must be exactly 16 characters, all digits, and start with 4
Examples
Input: ('4111111111111111',)
Expected Output: True
Explanation: This is a 16-digit number starting with 4 and it passes Luhn.
Input: ('4012888888881881',)
Expected Output: True
Explanation: Another valid VISA test number.
Input: ('4111111111111112',)
Expected Output: False
Explanation: The format is VISA-like, but the Luhn checksum fails.
Input: ('5100000000000008',)
Expected Output: False
Explanation: The number passes neither the VISA prefix rule nor the VISA network rule because it does not start with 4.
Input: ('',)
Expected Output: False
Explanation: Edge case: an empty string is not a valid card number.
Hints
- For Luhn, process digits from right to left and double every second digit.
- If a doubled digit becomes greater than 9, subtract 9 from it before adding to the checksum.
Part 2: Multi-Network Card Validation
Constraints
- 0 <= len(card_number) <= 32
- card_number may contain digits or other characters
- Network matching is based on exact length and prefix
- Checksum is evaluated only after a supported network pattern is matched
Examples
Input: ('4111111111111111',)
Expected Output: 'VISA'
Explanation: The number matches VISA rules and passes Luhn.
Input: ('5555555555554444',)
Expected Output: 'MASTERCARD'
Explanation: The prefix 55 and length 16 identify MASTERCARD, and the checksum is valid.
Input: ('378282246310005',)
Expected Output: 'AMEX'
Explanation: The prefix 37 and length 15 identify AMEX, and the checksum is valid.
Input: ('4111111111111112',)
Expected Output: 'INVALID_CHECKSUM'
Explanation: The number matches VISA format but fails the Luhn checksum.
Input: ('',)
Expected Output: 'UNKNOWN_NETWORK'
Explanation: Edge case: an empty input cannot match any supported card network.
Hints
- Separate the network-detection logic from the Luhn checksum logic.
- If a number has an unsupported length or prefix, do not run checksum-based classification; return UNKNOWN_NETWORK.
Part 3: Redacted Card Wildcard Completion Counts
Constraints
- 1 <= len(redacted) <= 16
- redacted contains only digits and * characters
- 1 <= number of * characters <= 5
- Supported networks use the same length, prefix, and Luhn rules as Part 2
Examples
Input: ('411111111111111*',)
Expected Output: [['AMEX', 0], ['MASTERCARD', 0], ['VISA', 1]]
Explanation: Only replacing * with 1 produces the valid VISA number 4111111111111111.
Input: ('41111111111111**',)
Expected Output: [['AMEX', 0], ['MASTERCARD', 0], ['VISA', 10]]
Explanation: The prefix and length force VISA; among the 100 endings, exactly 10 pass Luhn.
Input: ('5*55555555554444',)
Expected Output: [['AMEX', 0], ['MASTERCARD', 1], ['VISA', 0]]
Explanation: Only the completion with prefix 55 and a valid checksum is accepted.
Input: ('37828224631000*',)
Expected Output: [['AMEX', 1], ['MASTERCARD', 0], ['VISA', 0]]
Explanation: Only replacing * with 5 produces the valid AMEX number 378282246310005.
Input: ('****',)
Expected Output: [['AMEX', 0], ['MASTERCARD', 0], ['VISA', 0]]
Explanation: Edge case: no 4-digit completion can match any supported network length.
Hints
- With at most 5 wildcards, there are at most 100000 completions, which is small enough to enumerate directly.
- After filling the wildcards, reuse the same network-detection and Luhn validation steps.
Part 4: Corrupted Card Recovery
Constraints
- 1 <= len(corrupted) <= 17
- corrupted ends with ?
- All characters before ? are digits
- The observed number length is expected to be 15 or 16 for recoverable cards
- For a digit-change error, the original digit must be different from the observed digit
- For an adjacent-swap error, the swap must change the observed string, so equal adjacent digits do not generate a candidate
Examples
Input: ('6111111111111111?',)
Expected Output: [['4111111111111111', 'VISA']]
Explanation: Changing the first digit from 6 back to 4 recovers a valid VISA number.
Input: ('4909000000000004?',)
Expected Output: [['4099000000000004', 'VISA'], ['4900900000000004', 'VISA'], ['4990000000000004', 'VISA']]
Explanation: Several adjacent swaps involving 0 and 9 produce valid VISA originals; results are sorted numerically.
Input: ('840000000000009?',)
Expected Output: [['340000000000009', 'AMEX']]
Explanation: Changing the first digit from 8 back to 3 recovers a valid AMEX number.
Input: ('4111111111111111?',)
Expected Output: []
Explanation: Edge case: the observed number is valid, but no different valid original can be obtained by one digit change or one meaningful adjacent swap.
Hints
- Generate candidates by trying every single-position digit replacement and every adjacent swap, then validate each candidate.
- Use a set or dictionary to avoid returning the same valid original more than once.