Google Data Structures and Algorithms Interview Questions & Answers
Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.
About Google hiring for Data Structures and Algorithms roles
Google, part of Alphabet, builds products such as Search, YouTube, Android, Google Cloud, Maps and Pay. Its Indian offices contribute to engineering, cloud, payments and research work for local and global products. It hires in India for software engineers, test and reliability engineers, data scientists and analysts who work on large-scale data and experimentation.
For Data Structures and Algorithms roles, this Google practice set focuses most on Linked Lists, Stacks and Queues (7), Trees and Binary Search Trees (5), Heaps, Priority Queues and Greedy (4), Sorting, Searching and Backtracking (4). It has 2 easy, 18 medium, 10 hard questions, so you can start easy and work up to the harder ones.
Company type
Product
Headquarters
Mountain View, California, USA
Main India offices
Bengaluru, Hyderabad, Gurugram, Mumbai, Pune
Google Data Structures and Algorithms interview process
Recruiter screening
Online coding assessment or phone screen
Technical interviews (coding, 3-4 rounds)
Googleyness and leadership round
Hiring committee review
Typical pattern based on public candidate experiences. Rounds vary by role, team and year.
Solved for GoogleStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
✓ 3 questions free • Unlock the rest in seconds
01
An interviewer asks you to reduce your solution's extra space from O(n) to O(1). How do you approach it?
I check what the extra structure stores and whether the input itself can hold that information. Common techniques: use two pointers instead of a hash set on sorted data, keep only the last few DP values instead of a full table, modify the input in place, such as marking visited indices by negating values, or use bit manipulation like XOR to find a missing number. I state any trade-offs, such as mutating input.
import heapq
def merge_k_lists(lists):
heap = []
for i, node in enumerate(lists):
if node:
heapq.heappush(heap, (node.val, i, node)) # i breaks ties
dummy = tail = ListNode()
while heap:
val, i, node = heapq.heappop(heap)
tail.next = node
tail = node
if node.next:
heapq.heappush(heap, (node.next.val, i, node.next))
return dummy.next
# O(N log K) for N total nodes
03
Explain the sliding window technique with fixed and variable windows.
A sliding window keeps a contiguous range and updates its result incrementally instead of recomputing. A fixed window of size k, such as the maximum sum of k consecutive elements, adds the new element and removes the old one each step in O(n). A variable window grows the right end and shrinks the left end while a condition is violated, as in the longest substring without repeating characters. Both turn O(n squared) into O(n).
04
You need to merge K sorted log files from different servers into one sorted output. How would you do it efficiently?
Use a min-heap of size K holding the current smallest line from each file, keyed by timestamp. Pop the smallest, write it out, and push the next line from the same file. Each line is pushed and popped once, so total time is O(N log K) for N lines, and memory is O(K) plus buffers, which works even when files are larger than RAM. Buffered reading and writing keeps I/O efficient.
05
What is tail recursion and do Java and Python optimise it?
A call is tail recursive when the recursive call is the very last action, so nothing remains to be done after it returns, as in a factorial that carries an accumulator. Some languages reuse the same stack frame for such calls, turning recursion into a loop. Neither Java nor CPython performs tail call optimisation, so deep tail recursion still overflows; convert it to a loop manually.
06
How does Floyd's cycle detection algorithm work and why is it correct?
Floyd uses a slow pointer moving one step and a fast pointer moving two steps. If there is no cycle, fast reaches the end. If there is a cycle, fast gains one step per iteration on slow inside the loop, so they must meet. To find the cycle start, reset one pointer to the head and move both one step at a time; they meet at the start because the distances from head and from the meeting point are equal modulo the cycle length.
07
Generate all permutations of a list of distinct numbers using backtracking.
Situation: a senior reviewer rejected my pull request because my queue processing code was O(n squared) and had no tests. Task: fix it and learn from it. Action: I asked for a short walkthrough, replaced repeated list removals with a deque, added unit tests for edge cases and asked for a second review. Result: the change merged with a ten times speed-up, and I now self-review complexity and tests before raising any pull request.
09
Implement a data structure that returns the median of all numbers added so far.
I would use a trie where each node stores, besides children, the top few most popular completions under that prefix. Then typing a prefix walks L nodes and returns precomputed suggestions instantly, without exploring the whole subtree. Memory can be reduced with a compressed radix trie. For typo tolerance or ranking by many signals, a search engine with prefix indexes is more practical at large scale.
11
Design a rate limiter that allows at most 100 requests per user in any rolling 60-second window.
For each user keep a deque of request timestamps. On a request, pop timestamps older than now minus 60 seconds from the front, then allow the request only if fewer than 100 remain, pushing the new timestamp at the back. This sliding window log is exact but uses memory per request. At scale I would use a sliding window counter or token bucket stored in Redis with atomic operations to save memory and work across servers.
12
CPU tasks labelled by type must be scheduled with a cooldown of n slots between two tasks of the same type. How do you minimise total time?
Greedily run the most frequent available task each slot. Use a max-heap of remaining counts and a queue of tasks cooling down with the time they become available. Each slot, move ready tasks back to the heap, pop the most frequent, decrement and enqueue it with time plus n. A closed formula also exists: max of total tasks and (maxFreq minus 1) times (n plus 1) plus the number of tasks with maxFreq.
13
Your brute-force solution for the longest substring without repeating characters is O(n cubed). How would you improve it?
I would use a variable sliding window. Keep a map from character to its last index and a left pointer. Move the right pointer through the string; when the current character was seen at an index at or after left, move left to that index plus one. Update the best length at each step. Each character is processed a constant number of times, giving O(n) time and O(alphabet size) space.
14
A report generation function loops over all users and, for each user, scans all orders. It was fine at launch but is now very slow. How do you explain and fix it?
The loop is O(users times orders), so when both grow ten times, the work grows a hundred times. I would explain this with numbers and a quick profile. The fix is to group orders by user ID once using a hash map, making the total O(users plus orders), or to push the grouping into a database query with an index. I would add a performance test with production-scale data.
15
A sorted array has been rotated at an unknown point. How can you still search it in O(log n)?
At every step of binary search, at least one half around mid is sorted. Compare nums[low] with nums[mid]: if the left half is sorted and the target lies within its range, search left, otherwise search right. If the right half is sorted, apply the same check on the right. This keeps O(log n). With duplicates allowed, equal values can hide which half is sorted, and the worst case becomes O(n).
16
How can you implement a queue using two stacks, and what is its complexity?
Use an in-stack for enqueue and an out-stack for dequeue. Enqueue pushes onto the in-stack in O(1). For dequeue, if the out-stack is empty, pop everything from the in-stack and push it onto the out-stack, which reverses the order, then pop from the out-stack. Each element moves at most once between stacks, so dequeue is O(1) amortised even though a single transfer can be O(n).
17
What is the difference between a subarray, a subsequence and a substring?
A subarray is a contiguous part of an array, and an array of n elements has n times n plus 1 over 2 of them. A substring is the same idea for strings. A subsequence keeps the original order but may skip elements, so there are 2 to the power n of them. This matters for choosing techniques: sliding window and prefix sums suit subarrays, while subsequence problems often need dynamic programming.
18
You need to build a tool that shows the differences between two versions of a file line by line. What algorithm would you use?
The core is the longest common subsequence over lines: lines in the LCS are unchanged, and the rest are additions or deletions. Hash each line first so comparisons are fast. Classic LCS DP is O(m times n), which is too slow for large files, so real diff tools use Myers' algorithm, which runs in O((m plus n) times d), where d is the number of differences, fast when versions are similar.
19
What is Timsort and why do Python and Java use it?
Timsort is a hybrid of merge sort and insertion sort. It scans the data for already sorted runs, extends short runs with insertion sort and merges runs using a stack with balancing rules and galloping mode. Real data is often partially sorted, so Timsort is close to O(n) on such input while keeping O(n log n) worst case and stability. Python uses it for all sorts and Java for sorting objects.
20
Implement 0/1 knapsack using a one-dimensional DP array.
def knapsack(weights, values, capacity):
dp = [0] * (capacity + 1) # dp[w] = best value with capacity w
for wt, val in zip(weights, values):
for w in range(capacity, wt - 1, -1): # go downwards: each item once
dp[w] = max(dp[w], dp[w - wt] + val)
return dp[capacity]
# knapsack([1, 3, 4], [15, 20, 30], 4) -> 35
# O(n * W) time, O(W) space
21
How does cycle detection differ in directed and undirected graphs?
In an undirected graph, DFS finds a cycle when it reaches an already visited vertex that is not the parent of the current vertex; Union-Find also works by checking whether an edge joins vertices already in the same set. In a directed graph you need three states, unvisited, in the current recursion stack and finished, and a cycle exists when DFS reaches a vertex still on the stack. Kahn's algorithm also detects directed cycles.
22
Design a simple scheduler that gives each job a fixed time slice in turn.
Round-robin scheduling fits a queue. Put all jobs in a FIFO queue. Repeatedly dequeue a job, run it for one time slice, and if it is not finished, enqueue it at the back with its remaining time. Each step is O(1). For priorities, keep one queue per priority level or use a priority queue. A circular buffer works well if the number of jobs is bounded, avoiding allocations.
23
Tell me about an interview or exam you failed and what you learned.
Situation: I was rejected after a coding round because I could not solve a tree problem in time. Task: understand the gap honestly. Action: I wrote down the question, realised I memorised solutions instead of patterns, and reorganised my practice by patterns such as postorder aggregation and BFS by level, explaining each solution aloud. Result: three months later I cleared a similar round comfortably, and I now review every mistake within a day.
24
Implement topological sort using Kahn's algorithm.
from collections import deque
def topo_sort(n, edges):
adj = [[] for _ in range(n)]
indeg = [0] * n
for u, v in edges: # u must come before v
adj[u].append(v)
indeg[v] += 1
q = deque(i for i in range(n) if indeg[i] == 0)
order = []
while q:
u = q.popleft()
order.append(u)
for v in adj[u]:
indeg[v] -= 1
if indeg[v] == 0:
q.append(v)
return order if len(order) == n else [] # empty means a cycle exists
25
Find the next greater element for every element of an array.
def next_greater(nums):
res = [-1] * len(nums)
stack = [] # indices with decreasing values
for i, x in enumerate(nums):
while stack and nums[stack[-1]] < x:
res[stack.pop()] = x
stack.append(i)
return res
# [4, 5, 2, 25] -> [5, 25, 25, -1]
# Each index is pushed and popped once: O(n)
26
What is the difference between full, complete and perfect binary trees?
In a full binary tree every node has zero or two children. In a complete binary tree every level except possibly the last is completely filled, and the last level is filled from the left, which is exactly the shape of a binary heap and allows array storage. A perfect binary tree has all internal nodes with two children and all leaves at the same level, containing 2 to the power h plus 1, minus 1 nodes.
27
An application needs sorted data with frequent inserts, deletes and range queries such as all orders between two timestamps. Which structure fits?
A balanced BST, such as Java TreeMap or a sorted container in Python, gives O(log n) insert and delete and O(log n plus k) range queries using floor, ceiling or subMap operations. A sorted array has fast range queries but O(n) inserts, and a hash map cannot do ranges at all. If the data lives in a database, a B-tree index on the timestamp column solves the same problem.
28
A Sudoku solver using plain backtracking is too slow on hard puzzles. How would you speed it up?
Add stronger pruning and better choice ordering. Keep bitmasks of used digits for each row, column and box, so validity checks are O(1). Always fill the empty cell with the fewest candidates first, the minimum remaining values heuristic, which shrinks the search tree dramatically. Apply constraint propagation, filling cells with a single candidate before guessing. For the hardest cases, exact cover with Dancing Links is very fast.
29
Serialize a binary tree to a string and deserialize it back.
Keep a second stack of minimums. On push, push the value onto the main stack and push the smaller of the value and the current minimum onto the min stack. On pop, pop both. getMin returns the top of the min stack in O(1). To save space, push onto the min stack only when the new value is less than or equal to the current minimum, and pop it only when the popped value equals it.
Tips to crack the Google Data Structures and Algorithms interview
Practise solving DSA problems in a plain document without autocomplete, since Google interviews often use a shared editor without running code.
For data science roles, revise statistics, A/B testing and product metrics for products like YouTube, Search or Google Pay.
Prepare examples showing collaboration, handling ambiguity and doing the right thing, which the Googleyness round tends to explore.
Keep a one-minute story ready for every project on your CV: problem, your part, tools, result.
Practise the hard questions on this page aloud; Google interviewers usually ask follow-ups on your first answer.
Frequently asked questions
How many rounds are there in the Google Data Structures and Algorithms interview?
Candidates usually go through 5 stages: Recruiter screening; Online coding assessment or phone screen; Technical interviews (coding, 3-4 rounds); Googleyness and leadership round; Hiring committee review. The exact rounds change with the role, team, location and your experience, so confirm the process with the recruiter.
Which topics should I prepare for the Google Data Structures and Algorithms interview?
This practice set leans on Linked Lists, Stacks and Queues (7), Trees and Binary Search Trees (5), Heaps, Priority Queues and Greedy (4), Sorting, Searching and Backtracking (4). Revise those first, then practise explaining one or two of your own projects end to end, because most Google interviewers ask you to walk through real work.
Are these the exact questions asked at Google?
No. These are curated practice questions that match the skills and difficulty usually tested in product interviews like Google's. They are not a leaked or verified list of past questions.
Where does Google hire Data Structures and Algorithms professionals in India?
Google has large teams in Bengaluru, Hyderabad, Gurugram, Mumbai, Pune. Openings and locations change often, so check the Google careers page and filter by city and experience.
Data Structures and Algorithms questions for similar companies