← TCS Interview Insights

TCS·Data Scientist·Technical Phone Screen·Intermediate

Intermediate
Apr 2026

Summary

TCS Data Scientist interview that was basically one long algorithmic deep-dive on duplicate detection in Python lists. Pretty technical for a DS role, but they clearly wanted someone who could reason about complexity tradeoffs and not just pandas their way through everything.

Questions Asked (5)

Q1

Write an O(n) time solution to find all values appearing more than once in a Python list, along with their counts and first-occurrence index, preserving the order of first appearance.

Algorithms & Data Structures
Author's notes

Used a dict to track count and first index in one pass, then a separate list to preserve insertion order.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a single pass with a dictionary to track each element's count and first index, then filter for counts > 1 while preserving insertion order. Emphasize that Python 3.7+ dicts maintain insertion order, so the result naturally follows first appearance. Discuss time and space complexity, noting O(n) time and O(n) space.

Pro tip: Mention that if the list contains unhashable elements, you'd need a different approach, but for typical hashable data this is optimal. Also, clarify that 'first-occurrence index' refers to the index of the first time the element appears, not the first duplicate.

1. Clarify requirements and constraints

Confirm that the list contains hashable elements and that we need counts and first-occurrence indices for values appearing more than once. Ask about handling unhashable types or memory constraints.

2. Choose data structure and algorithm

Select a dictionary to map each element to a [count, first_index] pair. Explain that a single pass achieves O(n) time and O(n) space.

3. Implement the single-pass traversal

Iterate through the list with enumerate. For each element, if it's not in the dictionary, add it with count 1 and its index; otherwise, increment its count.

4. Filter and format results

After the pass, iterate through the dictionary items (which preserve insertion order) and collect those with count > 1 into a list of tuples or dictionaries containing value, count, and first index.

5. Analyze complexity and edge cases

State that time is O(n) and space is O(n). Discuss edge cases: empty list, no duplicates, all duplicates, and unhashable elements.

Key Points to Mention

  • Time complexity: O(n) due to single pass over the list.
  • Space complexity: O(n) for the dictionary storing counts and indices.
  • Use of Python's dictionary insertion order (Python 3.7+) to preserve first appearance order.
  • Handling of first-occurrence index: store index only when element is first seen.
  • Edge cases: empty list, no duplicates, all elements duplicate, unhashable elements.
  • Alternative approaches (e.g., using collections.Counter or defaultdict) and their trade-offs.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

If the integers are guaranteed to be in the range 0 to n-1 and you can modify the list in place, how would you find duplicates in O(n) time and O(1) extra space? How does your approach change if negative numbers might appear?

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

The index-negation trick came to mind fast but I fumbled the negative numbers part for a second.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Explain the in-place marking technique: iterate through the array, and for each element, use its value as an index to mark the presence of that number by negating the value at that index. If the value at that index is already negative, it indicates a duplicate. For negative numbers, first check if any negatives exist; if so, use an offset or a different marking strategy such as adding n to the value at the index, then taking modulo n to recover the original value.

Pro tip: Mention that the marking technique modifies the array but can be restored if needed, and discuss the trade-off between time and space complexity. Also, clarify that the O(1) space is extra space, not counting the input array.

1. Clarify constraints and assumptions

Confirm that the array contains integers in range 0 to n-1, and that we can modify the array in place. Ask if the output should be the list of duplicates or just a boolean indicating existence.

2. Explain the in-place marking algorithm

For each element, treat its value as an index. If the value at that index is positive, negate it to mark presence. If it's already negative, the current value is a duplicate. This uses O(n) time and O(1) extra space.

3. Handle negative numbers

If negative numbers might appear, first check if any negative exists. If so, use an offset: add n to the value at the index (mod n) to mark, or shift all numbers by a constant to make them non-negative. Alternatively, use a separate boolean array if extra space is allowed, but that violates O(1).

4. Discuss trade-offs and edge cases

Mention that the marking technique destroys the original array unless restored. Discuss edge cases: all unique, all duplicates, multiple duplicates, and the presence of zero. Also, note that if the range is not 0 to n-1, the technique fails.

5. Summarize and conclude

Reiterate that the approach achieves O(n) time and O(1) extra space by using the array itself as a hash table. For negative numbers, an offset or modulo trick can be applied, but it may require additional passes.

Key Points to Mention

  • In-place marking using negation or adding n
  • Time complexity O(n) and extra space O(1)
  • Handling duplicates: detecting when a value is already marked
  • Negative numbers: using offset or modulo to handle
  • Trade-off: modifying input array vs. using extra space
  • Edge cases: zeros, multiple duplicates, all elements same

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

For a stream of up to 100 million integers that can't fit in memory, how would you design a solution to find duplicates? Walk through both disk-based and probabilistic approaches and discuss error bounds.

System DesignAlgorithms & Data Structures
Author's notes

This is where I went off-script a bit.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying constraints (memory, disk, time, exact vs approximate). Then present a disk-based external sort or hash partitioning approach for exact duplicate detection, followed by probabilistic methods like Bloom filters or HyperLogLog for approximate detection with error bounds. Compare trade-offs and recommend a hybrid if appropriate.

Pro tip: Quantify the error bounds and resource usage (e.g., false positive rate of Bloom filter, memory for HyperLogLog) to show you understand the practical implications. Mention that in production, a hybrid approach often balances accuracy and efficiency.

1. Clarify Requirements

Ask about memory limits, disk space, time constraints, and whether exact or approximate duplicates are needed. This determines the approach.

2. Disk-Based Exact Approach

Describe external sorting or hash partitioning: split the stream into chunks that fit in memory, sort each chunk, write to disk, then merge and detect duplicates. Alternatively, hash integers into partitions and process each partition separately.

3. Probabilistic Approximate Approach

Explain using a Bloom filter to track seen integers with a small false positive rate, or HyperLogLog to estimate cardinality and infer duplicates. Discuss error bounds and memory trade-offs.

4. Compare and Recommend

Compare disk-based (exact, slower, more I/O) vs probabilistic (approximate, faster, less memory). Suggest a hybrid: use Bloom filter to filter likely duplicates, then verify with disk-based method.

5. Discuss Error Bounds and Scalability

For Bloom filter, false positive rate p = (1 - e^(-kn/m))^k; for HyperLogLog, standard error ~1.04/√m. Explain how to tune parameters for 100M integers.

Key Points to Mention

  • External sorting or hash partitioning for exact duplicate detection
  • Bloom filter: false positive rate, no false negatives, memory usage
  • HyperLogLog: cardinality estimation, standard error, memory efficiency
  • Trade-offs: exact vs approximate, time vs memory, disk I/O
  • Hybrid approach: Bloom filter + disk verification
  • Scalability: handling 100M integers with limited memory

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Compare hash-based counting, sort-based methods, and bitmap approaches for duplicate detection across large integer domains. What are the worst-case behaviors and cache implications of each?

Technical Trade-offsAlgorithms & Data Structures
Author's notes

Sort-based is O(n log n) but cache-friendly once sorted, hash maps are O(n) average but can degrade badly with collisions and have poor locality, bitmaps are great for dense integer domains but blow up in memory for sparse ones.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining the problem scope: large integer domains, duplicate detection, and the need to compare hash-based counting, sort-based methods, and bitmap approaches. For each method, describe the algorithm, then analyze worst-case time and space complexity, and discuss cache behavior (locality, misses). Conclude with practical recommendations based on domain size, memory constraints, and performance requirements.

Pro tip: Emphasize that bitmap is only feasible when the integer domain is dense and bounded; for sparse or unbounded domains, hash or sort-based methods are more practical. Mention that cache behavior often dominates performance in large-scale duplicate detection, so choose algorithms with good locality.

1. Define the problem and constraints

Clarify the integer domain size, density, memory limits, and whether duplicates are exact. This sets the context for comparing methods.

2. Describe each method briefly

Explain hash-based counting (hash table with counts), sort-based (sort then scan), and bitmap (bit array indexed by integer). Keep it concise.

3. Analyze worst-case time and space

For each, state worst-case time (e.g., hash: O(n) average but O(n^2) worst-case with collisions; sort: O(n log n); bitmap: O(n) but space O(U)) and space (hash: O(k) distinct; sort: O(n) or O(1) extra; bitmap: O(U/8)).

4. Discuss cache implications

Compare memory access patterns: hash tables have random access causing cache misses; sorting has sequential access but may incur multiple passes; bitmap has random access but compact size improves cache utilization.

5. Summarize trade-offs and recommend

Conclude which method suits which scenario: bitmap for dense small domains, hash for sparse and fast average-case, sort for external memory or when order matters.

Key Points to Mention

  • Hash-based counting: average O(n) time, O(k) space; worst-case O(n^2) due to collisions; cache-unfriendly due to random access.
  • Sort-based: O(n log n) time, O(n) space (or O(1) with in-place sort); good cache locality during merge but initial sort may have poor locality.
  • Bitmap: O(n) time, O(U/8) space; extremely fast and cache-friendly if U is small, but infeasible for large or sparse domains.
  • Worst-case behaviors: hash collisions can degrade to linear search; sort worst-case is guaranteed O(n log n); bitmap worst-case is memory blow-up if U is huge.
  • Cache implications: hash tables cause many cache misses; sorting benefits from sequential access; bitmap has random access but compact size means fewer cache lines.
  • Practical considerations: use bitmap when domain is dense and fits in memory; use hash when domain is sparse and average-case performance is acceptable; use sort when memory is limited or external sorting is needed.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

Write comprehensive tests for your duplicate-finding function, covering edge cases like empty input, all-unique values, all-duplicates, very large inputs, and mixed positive/negative integers.

Algorithms & Data Structures
Author's notes

Straightforward but easy to rush.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the function's contract and expected behavior, then systematically design test cases that cover normal operation, edge cases, and performance. Use a structured test suite with clear naming and assertions, and discuss how you would validate correctness and efficiency.

Pro tip: Mention that you would use property-based testing (e.g., Hypothesis) to automatically generate diverse inputs and catch unexpected edge cases, and that you would also test for time and space complexity to ensure scalability.

1. Understand the function

Clarify the function's signature, return type, and expected behavior for duplicates (e.g., return list of duplicates, count, or boolean). Confirm assumptions about input types and constraints.

2. Identify test categories

List categories: empty input, all unique, all duplicates, mixed positive/negative, large inputs, and possibly single element, two elements, and inputs with multiple duplicates.

3. Design specific test cases

For each category, create concrete examples with expected outputs. Include boundary cases like maximum integer values and inputs with zero.

4. Implement tests

Write test functions using a framework like pytest or unittest, with descriptive names and assertions. Use parameterization to cover multiple cases efficiently.

5. Validate and iterate

Run tests, ensure they pass, and consider adding performance tests for large inputs. Discuss how you would handle failures and refine tests.

Key Points to Mention

  • Clarify the function's contract and expected behavior before writing tests.
  • Cover edge cases: empty input, all unique, all duplicates, single element, two elements.
  • Test with mixed positive and negative integers, including zero and boundary values.
  • Include large inputs to test performance and scalability (e.g., time and space complexity).
  • Use parameterized tests to avoid repetition and improve maintainability.
  • Consider property-based testing to generate random inputs and verify invariants.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.