Arrays, Strings & Hashing
- Reach for a hash map or set the instant a problem needs "have I seen this, in O(1)"
- Use a stack to match pairs and to find the next greater element or the widest span
- Build a hard problem up from a known one: maximal rectangle is just a histogram swept row by row
- Treat string problems as careful implementation, where the edge cases carry the grade
These are the warm-ups that open a Google coding round and the spans-and-matching problems that turn into the hard one. They run from a one-minute hash map to a Hard that stacks three ideas on top of each other. None of them are exotic. Google grades whether you reach the right structure on instinct. You then explain why it works while you type into a Google Doc that will not run your code.
Three structures cover this group. A hash map or set answers "have I seen this key" in constant time, which kills nested-loop scans. A stack matches things that nest, like brackets, and remembers what is still open. A monotonic stack or deque stays sorted as you push. In a single pass it answers "what is the next greater element" or "how wide a span can this value command." Learn those three. The rest is bookkeeping.
How Google frames it
Google does not hand you the textbook title. It buries the problem inside a business scenario and trusts you to recognize the shape underneath. Two Sum arrives as "match each ad request to the one budget line that fills it." Valid Parentheses becomes "validate that these nested config blocks open and close correctly." Same algorithm. The business framing is there to slow you down. Cut past the scenario to the structure fast, then name it and reason about edge cases before you write a line. That speed is what they're watching for.
Nothing in the Doc runs. You win the round out loud instead. Write the solution, then walk one short input through it by hand and name the invariant, the rule your structure never breaks: "the stack always holds exactly the brackets still waiting to close." A candidate who only memorized a template can't produce that line. One who understands the structure says it without thinking. And it's the only proof of correctness anyone in the room gets.
Each structure trades a little memory for a single pass. A hash map remembers what you have already seen so you never re-scan. A stack remembers what is still open so you never re-search for a match. A monotonic stack remembers the candidates still in play so you never recompute a span. Say a problem asks you to find the pair, validate the nesting, or find the largest area. The first question to ask is what you would have to remember to answer it in one sweep. The answer is almost always one of these three.
The three structures to know
Nearly everything in this group is one of these three, or a small mix of them.
Pattern 1: Hash map or set for O(1) lookup
A hash map (Python's dict) stores key-to-value pairs and looks any key up in roughly O(1) time; a hash set does the same for bare membership. You walk the array once and, at each element, ask the structure a question it answers instantly: have I seen the complement I need? Is this value's neighbor present? You write into the structure as you go, so each element both queries and updates it.
def two_sum(nums, target): seen = {} # value -> index, filled as we go for i, n in enumerate(nums): need = target - n # the partner that completes the pair if need in seen: # O(1) lookup: have we passed it already? return [seen[need], i] seen[n] = i # remember this value for a later element return []The brute force checks every pair, which is O(n²). The map collapses that to O(n) by remembering each value the instant you pass it, so the partner check is one lookup instead of a rescan. The same instinct powers the consecutive-sequence problem below, where a hash set turns an O(n log n) sort into a clean O(n) sweep.
Pattern 2: Stack for matching what nests
A stack is last-in, first-out: you push items on and pop the most recent one off. That ordering is exactly what nesting needs. When you read an opener you push it; when you read a closer the thing it must match is whatever you pushed most recently, sitting right on top. The stack always holds precisely the items still waiting to be closed, in the order they were opened.
def is_valid(s): pairs = {')': '(', ']': '[', '}': '{'} # closer -> its opener stack = [] for ch in s: if ch in pairs: # a closer: top of stack must be its opener if not stack or stack.pop() != pairs[ch]: return False else: stack.append(ch) # an opener: remember it until its closer arrives return not stack # any leftover openers -> unbalancedThe invariant carries the proof. At every step the stack holds exactly the unmatched openers seen so far. A closer that finds the wrong opener on top, or an empty stack, means the string was never balanced. State that sentence and the correctness argument is finished.
Pattern 3: Monotonic stack for next greater and widest span
A monotonic stack keeps its contents sorted (here, by height) as you push. Before pushing a new bar you pop every bar that is taller than or equal to it. That incoming shorter bar is the wall that finally stops each of them from extending right. The moment a bar pops, you know both edges of the widest rectangle it can anchor, so you compute its area on the spot. Each bar is pushed once and popped once, so the sweep runs O(n) overall.
def largest_rectangle_area(heights): stack = [] # (start_index, height), heights increasing bottom->top best = 0 for i, h in enumerate(heights + [0]): # trailing 0 forces the stack to flush at the end start = i while stack and stack[-1][1] >= h: # this shorter bar stops every taller bar to its left idx, height = stack.pop() best = max(best, height * (i - idx)) # width runs from idx up to here start = idx # the new bar can extend left to where that taller bar began stack.append((start, h)) return bestThis histogram routine is the engine behind Maximal Rectangle below, the highest-frequency hard problem in this group. The same "pop until the new value breaks the order" mechanic, on a deque instead of a stack, gives the sliding-window maximum at the end. The Foundations stack lesson drills the base mechanics; here we go straight to the spins Google puts on it.
Asked at Google
Four problems, hardest structure last. Two Sum is the hash-map warm-up and Longest Consecutive Sequence is the hash-set trick. Valid Parentheses is the canonical stack, and Maximal Rectangle stacks the monotonic histogram on top of a row sweep. Read each spec twice. Say your edge cases before you type.
Two Sum: One-Pass Hash Map
Problem
nums and an integer target, return the indices of the two numbers that add up to target. Exactly one valid pair exists, and you may not use the same element twice. Return the indices in any order.Input: nums = [2,7,11,15], target = 9
Output: [0,1]
nums[0] + nums[1] = 2 + 7 = 9.
Input: nums = [3,2,4], target = 6
Output: [1,2]
nums[1] + nums[2] = 2 + 4 = 6; the two 3s would reuse one index.
For each number, the partner you need is target minus it. Keep a hash map from value to index, and check for that partner before you store the current number.
Two Sum: One-Pass Hash Map
Click "Run" to execute your code
Test Cases
[2,7,11,15], 9Expected: [0, 1][3,2,4], 6Expected: [1, 2][3,3], 6Expected: [0, 1]Longest Consecutive Sequence: Hash Set Run-Starts
Problem
nums, return the length of the longest run of consecutive integers (for example 1, 2, 3, 4) that can be formed from its values. The elements do not need to be adjacent in the array. Solve it in O(n) time.Input: nums = [100,4,200,1,3,2]
Output: 4
The run 1, 2, 3, 4 has length 4. 100 and 200 are isolated.
Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9
The run 0 through 8 has length 9; the duplicate 0 does not extend it.
Drop everything into a hash set. Then only begin counting a run at a number whose predecessor is absent, so each run is measured exactly once. That guard is what makes it O(n) instead of O(n log n).
Longest Consecutive Sequence: Hash Set Run-Starts
Click "Run" to execute your code
Test Cases
[[100,4,200,1,3,2]]Expected: 4[[0,3,7,2,5,8,4,6,0,1]]Expected: 9[[]]Expected: 0[[1,2,0,1]]Expected: 3n - 1 is absent from the set. Most people see a loop inside a loop and assume it's quadratic. Explain why that guard keeps the total work linear, because the Doc won't run it to prove you right.range(start, start + best_length), since the set guarantees every value in between is present.Valid Parentheses: Stack Matching
Problem
s of the characters (, ), {, }, [ and ], decide whether it is valid. It is valid when every closer matches the most recent unmatched opener of the same type, and every opener is eventually closed.Input: s = "()[]{}"
Output: true
Each closer matches the opener directly before it.
Input: s = "([)]"
Output: false
The brackets cross instead of nesting: the ) tries to close a [.
Input: s = "{[]}"
Output: true
Properly nested: the inner [] closes before the outer {}.
Push every opener onto a stack. On a closer, the matching opener must be on top: pop and compare. If the top is wrong or the stack is empty, it is invalid. A non-empty stack at the end means unclosed openers.
Valid Parentheses: Stack Matching
Click "Run" to execute your code
Test Cases
"()[]{}"Expected: True"([)]"Expected: False"{[]}"Expected: True"]"Expected: False"("Expected: Falseopen_needed, the unmatched closers that need an opener inserted before them, and open_count, the openers still waiting. Each unmatchable closer bumps open_needed; whatever openers remain at the end each need a closer. The answer is their sum.Maximal Rectangle: Monotonic Stack
Problem
'0' and '1' characters, find the largest rectangle made entirely of '1's and return its area.Input: matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
Output: 6
The 2-by-3 block in the bottom-left region of the dense rows has area 6.
Input: matrix = [["0"]]
Output: 0
No 1s, so no rectangle.
Treat each row as the ground of a histogram: heights[c] is the count of consecutive 1s ending at this row in column c. The answer is the largest rectangle across all those histograms, and each histogram is solved with a monotonic stack.
Maximal Rectangle: Monotonic Stack
Click "Run" to execute your code
Test Cases
[[["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]]Expected: 6[[["0"]]]Expected: 0[[["1"]]]Expected: 1[[["1","1"],["1","1"]]]Expected: 4dp[r][c] is the side of the largest square whose bottom-right corner is (r, c), computed as 1 + min(dp[r-1][c], dp[r][c-1], dp[r-1][c-1]) when the cell is a 1. The answer is the largest side squared. That is O(rows times cols) with no stack at all.Strings and simulation
String and simulation problems are graded on care. There's rarely a slick algorithm to find. The difficulty is in the bookkeeping. An off-by-one in the spacing, a last line that behaves differently, the single-word input nobody planned for. Google reaches for these to see whether your code survives contact with the messy details.
Two skills carry most of them. Parse the input cleanly so stray whitespace never bites you. The other is spreading a fixed number of spaces across a fixed number of gaps: do the division once, then hand the remainder out one unit at a time. Get those right and the rest is following the spec.
How Google frames strings
Because the algorithm is simple, Google watches your edge-case discipline instead. In Text Justification the last line is left-justified, a single-word line pads on the right, and uneven spaces favor the left gaps. Miss any one and the output is wrong. The escalation trades the easy greedy approach for an optimal one that breaks the lines to minimize total raggedness with a DP. The base problem is about getting every space right. The twist is spotting the optimization hiding under it.
The spacing math is one line: base, extra = divmod(total_spaces, gaps). Every gap gets base spaces, and the first extra gaps get one more. Spread evenly, remainder to the left. Both problems below run on it, and so does full justification everywhere.
The two moves to know
Almost every problem here mixes these two.
Pattern 1: Parse, then rebuild
Don't fight raw whitespace; tokenize first. Python's split() with no argument drops every run of spaces and ignores leading and trailing ones, leaving clean words. Then you rebuild the output with exactly the spacing the problem wants.
def normalize(text): words = text.split() # splits on any run of whitespace; no empty tokens return ' '.join(words) # rebuild with exactly one space between wordsSeparate parsing from formatting and the problem shrinks. Once words is a clean list, every spacing decision is arithmetic on its length, with no stray-space special cases left to trip on.
Pattern 2: Distribute with a remainder
Spreading N spaces across K gaps as evenly as possible is one divmod. Every gap gets the quotient; the remainder is handed out one extra unit at a time, to the leftmost gaps first (the convention full justification uses).
divmod(7, 2) = (3, 1): every gap gets 3, and the single leftover widens the first gap to 4.def distribute(total, gaps): base, extra = divmod(total, gaps) # base per gap; 'extra' units left over # the first 'extra' gaps get one more than the rest return [base + (1 if i < extra else 0) for i in range(gaps)]These are pure implementation problems, less algorithm than care; the Foundations course covers the string and array basics. Here we'll nail the spec and the edges.
String problems asked at Google
Two problems: the gentle distribute-with-remainder, then the full justification that adds line breaking on top. Read the spec twice and list the edge cases before you type.
Rearrange Spaces: Even Distribution
Problem
text of words separated by one or more spaces (with possible leading or trailing spaces), redistribute the spaces so the same maximal number sits between every pair of adjacent words, with any leftover spaces appended at the end. If there is only one word, all the spaces go after it.Input: text = " this is a sentence "
Output: "this is a sentence"
9 spaces, 3 gaps: 3 per gap, 0 left over.
Input: text = " practice makes perfect"
Output: "practice makes perfect "
7 spaces, 2 gaps: 3 per gap, 1 trailing.
Count the total spaces, split into words, then divmod(spaces, gaps): base spaces between each pair, remainder trailing. One word means every space trails it.
Rearrange Spaces: Even Distribution
Click "Run" to execute your code
Test Cases
" this is a sentence "Expected: "this is a sentence"" practice makes perfect"Expected: "practice makes perfect "" hello "Expected: "hello "base, extra = divmod(spaces, gaps), but give the first extra gaps one more space each and leave nothing at the end.Text Justification: Greedy Fill
Problem
words and a width maxWidth, format the text so every line is exactly maxWidth characters and fully justified. Greedily pack as many words per line as fit, distribute spaces between them as evenly as possible with any extras going to the leftmost gaps, and left-justify the final line. A line holding a single word is left-justified (padded on the right).Input: words = ["This","is","an","example","of","text","justification."], maxWidth = 16
Output: ["This is an","example of text","justification. "]
Each non-final line is padded to 16; the last line is left-justified.
Two phases. Greedily group words into lines (a word fits if current length + word lengths + one space between each <= width), then justify each line by spreading the leftover spaces across its gaps with divmod.
Text Justification: Greedy Fill
Click "Run" to execute your code
Test Cases
["This","is","an","example","of","text","justification."], 16Expected: ["This is an", "example of text", "justification. "]["What","must","be","acknowledgment","shall","be"], 16Expected: ["What must be", "acknowledgment ", "shall be "]dp[i] is the best layout of words[i:], trying every possible line-ending word j.Key Takeaways
- ✓Reach for a hash map or set the moment a problem needs "have I seen this key" in one pass; it collapses nested-loop scans to O(n).
- ✓A stack matches what nests: push openers, pop on closers, and the invariant "the stack holds exactly the unmatched openers" is your correctness proof on a no-run Doc.
- ✓Maximal Rectangle is Largest Rectangle in Histogram run once per row; stating that decomposition, and the monotonic-stack pop, is most of the solve.
- ✓String and simulation problems reward care over cleverness: parse then rebuild with split(), and read the spec twice before you type.
- ✓The spacing math is one line: base, extra = divmod(total, gaps), with extras handed to the leftmost gaps, and the special lines (last line, single-word) are always left-justified.
- ✓Google restates these as business scenarios and ladders the follow-up; the base answer never transfers, only the pattern does, so name the structure and adapt.
Google interview guideKnow what Google asks before you walk in.
34 coding · 7 system design · 47 behavioral questions
Get their questions first.
InterviewLegend is independent and not affiliated with or endorsed by any company it covers.