Software Engineer interview questions
100 real questions with model answers and explanations for Junior candidates.
See a Software Engineer resume example →Practice with flashcards
Spaced repetition · Hunter Pass
Questions
Big O notation expresses how an algorithm's time or memory use scales with input size.
- It ignores constants and lower-order terms so engineers can compare approaches independently of hardware.
- An O(n) scan eventually outscales an O(n^2) nested loop, even when the slower approach wins on tiny inputs.
- It helps predict when code that handles 100 rows will become too slow or memory-hungry at a million rows.
Why interviewers ask this: The interviewer checks whether you can reason about scalability abstractly rather than just measuring wall-clock time on small inputs.
Arrays favor fast indexed access, while linked lists favor insertion or deletion at already known nodes.
- An array stores elements contiguously, providing O(1) indexing and cache-friendly iteration.
- Inserting into an array's middle is O(n) because later elements shift, while a linked-list update at a known node is O(1).
- Reaching the k-th linked-list element takes O(n), so arrays fit random access and linked lists fit frequent edits at known positions.
Why interviewers ask this: A strong answer ties the memory layout to concrete access costs, while a weak one just recites definitions without the O(1) versus O(n) trade-off.
A hash table achieves average O(1) lookup by hashing a key directly to a bucket in an underlying array.
- Direct bucket access avoids scanning every stored entry.
- Uniform hash distribution and a low load factor keep only a few entries in each bucket.
- O(1) is an average rather than a guarantee, because poor hashing or a high load factor can degrade lookup toward O(n).
Why interviewers ask this: This tests whether you understand that O(1) depends on good hash distribution and load factor, not that it is magic.
A hash-table collision occurs when distinct keys map to the same bucket index.
- Separate chaining stores colliding entries in a small collection within the bucket and scans it during lookup.
- Open addressing probes other slots through methods such as linear, quadratic, or double hashing.
- Java HashMap uses chaining and can convert long chains into balanced trees to keep worst-case lookup near O(log n).
Why interviewers ask this: The interviewer wants to see you know collisions are inevitable and can name at least one concrete resolution strategy rather than assuming keys never clash.
A stack removes items in LIFO order, while a queue removes them in FIFO order.
- A stack returns the most recently pushed item first, as in nested function calls or browser back navigation.
- A queue returns the earliest enqueued item first, as in print jobs or tasks waiting for workers.
- Both can provide O(1) insertion and removal, but they remove items from different ends of the sequence.
Why interviewers ask this: A strong candidate pairs each structure with a genuine use case, showing they connect the abstract order to real systems.
Binary search finds a target in sorted data by discarding half of the remaining range after each comparison.
- It compares the target with the middle element and runs in O(log n) time.
- The data must already be sorted by the search key, or the decision to discard either half is invalid.
- Sorting first costs O(n log n), so binary search is especially useful for repeated searches over the same sorted data.
Why interviewers ask this: Forgetting the sorted precondition is the classic mistake this question is designed to catch.
Search in a balanced binary search tree takes O(log n) because each comparison discards an entire subtree.
- The number of search steps is bounded by the tree's height.
- A balanced tree keeps that height proportional to log n.
- An unbalanced tree can degenerate into a linked list with O(n) search, so AVL and red-black trees actively maintain balance.
Why interviewers ask this: The distinction between balanced O(log n) and degenerate O(n) is exactly what separates a precise answer from a vague one.
Recursion is a technique in which a function solves a problem by calling itself with a smaller version of that problem.
- A base case must stop the recursive calls.
- A recursive case must reduce the input and make progress toward the base case.
- A missing or unreachable base case causes unbounded calls and eventually a stack overflow because every call consumes stack memory.
Why interviewers ask this: Naming both the base case and the progress toward it shows you understand why recursion terminates rather than just what it looks like.
A tree is a constrained kind of graph, while a graph can represent more general connections.
- A graph contains nodes and edges and may be directed or undirected, cyclic or acyclic.
- A tree is connected, has no cycles, and has exactly one path between every pair of nodes.
- A tree with n nodes has n minus one edges, so every tree is a graph but most graphs are not trees.
Why interviewers ask this: A strong answer frames a tree as a constrained graph, revealing you grasp the hierarchy rather than treating them as unrelated.
Breadth-first search explores level by level, while depth-first search follows one branch before backtracking.
- BFS uses a queue and finds shortest paths in an unweighted graph.
- DFS uses a stack or recursion and suits cycle detection, topological sorting, and exploration of all paths.
- Both take O(V + E), but BFS memory follows the widest level while DFS memory follows the deepest path.
Why interviewers ask this: The interviewer looks for the queue-versus-stack mechanism plus a correct problem where each one is the better fit.
Quicksort partitions an array around a pivot and recursively sorts the two resulting parts.
- Elements smaller than the pivot move left and larger elements move right.
- Good pivots produce roughly even partitions and an average complexity of O(n log n).
- Consistently choosing an extreme element causes O(n^2) behavior, although randomized or median-of-three pivots make this unlikely in practice.
Why interviewers ask this: Knowing both the average O(n log n) and the O(n^2) worst case, plus what triggers it, shows depth beyond memorizing one number.
A stable sorting algorithm preserves the relative order of elements that compare as equal.
- Stability matters when sorts are applied by multiple keys in sequence.
- After sorting by date and then stably by name, records with equal names retain their date order.
- Merge sort is stable while naive quicksort is not, so algorithm choice can determine whether a later sort preserves an earlier ordering.
Why interviewers ask this: A strong answer gives a multi-key sorting scenario, proving stability is a practical property and not just trivia.
Stack memory holds short-lived call data, while heap memory holds dynamically allocated data with more flexible lifetimes.
- The stack stores call frames, local variables, and return addresses and releases them automatically in LIFO order.
- Stack allocation is fast but limited in size, whereas the heap is larger but slower and can suffer fragmentation or leaks.
- Heap data can outlive the function that created it, while stack data is normally tied to its scope and call lifetime.
Why interviewers ask this: This checks whether you connect the two regions to lifetime and allocation cost rather than confusing them with the stack and heap data structures.
I would check a palindrome with two pointers moving inward from opposite ends of the string.
- Each step compares the current pair of characters and returns false on the first mismatch.
- The approach takes O(n) time and O(1) extra space, unlike creating a reversed copy with O(n) extra memory.
- If the definition requires it, I would first normalize letter case and ignore non-alphanumeric characters.
Why interviewers ask this: The two-pointer O(1)-space solution versus the naive reverse-and-compare is what separates an efficient answer from a working but wasteful one.
Floyd's tortoise-and-hare algorithm detects a linked-list cycle without extra storage.
- One pointer advances by one node per step while another advances by two.
- If a cycle exists, the fast pointer eventually laps and meets the slow pointer; reaching null means there is no cycle.
- The algorithm uses O(n) time and O(1) space, unlike a visited-node hash set that requires O(n) memory.
Why interviewers ask this: Naming the two-pointer trick and its O(1) space is exactly what the without-extra-memory constraint is probing for.
A stack is the natural structure for undo because the latest action must be reversed first.
- Every action pushes its previous state or an inverse command onto the undo stack.
- Undo pops and applies the top entry, matching LIFO order.
- A second stack enables redo by storing undone actions until they need to be replayed.
Why interviewers ask this: The interviewer wants the LIFO reasoning that maps undo order to a stack, plus the bonus insight of a second stack for redo.
Appending to a dynamic array is O(1) amortized because expensive resizes happen increasingly rarely.
- A full array typically doubles its capacity and copies all n existing elements in O(n).
- Exponential growth leaves many cheap O(1) appends between consecutive resizes.
- Spreading the total copying cost across all appends yields a constant average cost per operation.
Why interviewers ask this: Understanding amortized analysis, that doubling makes the expensive step rare enough to average to constant, is what this question isolates.
A set is an unordered collection of unique elements designed for fast membership checks.
- A hash-table-backed set usually tests membership in O(1), while a list requires an O(n) scan.
- A set is preferable when duplicates must be removed or presence must be checked repeatedly.
- Typical uses include deduplicating user IDs and recording visited values during graph traversal.
Why interviewers ask this: A strong answer highlights the O(1) membership test as the reason to prefer a set, not just that it removes duplicates.
Repeated string concatenation is often slow because immutable strings must be copied into a new value after every append.
- In Java and Python, building a growing string this way inside a loop can cost O(n^2) overall.
- A mutable buffer such as Java StringBuilder, or a Python list combined with str.join, accumulates pieces cheaply.
- Creating the final string only once at the end reduces the total work to O(n).
Why interviewers ask this: Recognizing the hidden O(n^2) from immutable copies and naming the buffer-based O(n) fix is what marks real understanding here.
A heap is a priority-queue structure that keeps its smallest or largest element at the root.
- It provides O(1) access to the extreme element and O(log n) insertion and removal.
- It efficiently returns the next highest-priority item without fully sorting all stored items.
- Common uses include task scheduling, merging sorted streams, and selecting the closest unvisited node in Dijkstra's algorithm.
Why interviewers ask this: The interviewer checks that you tie the heap's O(log n) operations to a repeated-minimum-or-maximum problem rather than defining it in isolation.
Locked questions
- 21
What are the four pillars of object-oriented programming?
oop - 22
What is the difference between a class and an object?
oop - 23
What is the difference between inheritance and composition, and why is composition often preferred?
oopownership - 24
What is polymorphism? Give a concrete example.
oop - 25
What is encapsulation and what problems does it prevent?
oop - 26
What is the difference between an abstract class and an interface?
types - 27
What is the difference between method overloading and method overriding?
oop - 28
Name the SOLID principles and explain one of them in detail.
solid - 29
What is dependency injection and why is it useful?
injectiondependencies - 30
What is a static method, and when is it appropriate to use one?
oop - 31
What are the key differences between object-oriented and functional programming?
oopfunctional - 32
What is a pure function, and why are pure functions easier to test?
functional - 33
What is the difference between compiled and interpreted languages?
fundamentals - 34
What is the difference between static and dynamic typing, and what are the trade-offs?
types - 35
How does garbage collection work at a high level?
gc - 36
What is a memory leak, and can it happen in a garbage-collected language?
memorygc - 37
How does exception handling work, and what are good practices for using try/catch?
error-handling - 38
What is the difference between pass by value and pass by reference?
fundamentals - 39
Why are null values a common source of bugs, and how do you defend against them?
fundamentals - 40
What is the difference between mutable and immutable data, and why does immutability help?
immutability - 41
What is variable scope, and why are global variables discouraged?
scope - 42
What is a race condition, and in what situations can a junior engineer run into one?
concurrency - 43
Why do teams use version control, and what problems does it solve?
git - 44
What is the difference between git merge and git rebase?
git - 45
What is a merge conflict, and how do you resolve one safely?
git - 46
Describe a feature branch workflow from starting a task to getting it merged.
git - 47
What does git pull actually do under the hood?
git - 48
How do you undo a change that has already been committed, and when would you use revert instead of reset?
git - 49
What makes a good commit, in terms of both size and message?
git - 50
What is .gitignore for, and what kinds of files should never be committed?
git - 51
What is the difference between unit, integration, and end-to-end tests?
e2e - 52
What properties make a unit test good?
unit - 53
What is the difference between a mock and a stub, and when do you use them?
mocking - 54
What is test-driven development, and what does the red-green-refactor cycle look like?
refactoring - 55
What is code coverage, and why is 100 percent coverage not a guarantee of quality?
coverage - 56
You are testing a function that divides two numbers. What test cases do you write?
test-cases - 57
Why should you write a test when you fix a bug?
- 58
What is a flaky test, and how do you deal with one?
flaky - 59
Walk me through your process when your code throws an error you have never seen before.
concurrency - 60
When is a debugger more effective than print statements, and when are print statements fine?
debugging - 61
How do you debug a problem that reproduces in production but not on your machine?
debugging - 62
What is a stack trace, and how do you read one to find the source of an error?
debugging - 63
The code worked yesterday and is broken today. How do you find which change broke it?
debugging - 64
A user reports a bug you cannot reproduce. What are your next steps?
debugging - 65
What is a primary key, and what makes a good one?
primary-keys - 66
What is the difference between INNER JOIN and LEFT JOIN?
joins - 67
What are aggregate functions and GROUP BY used for? Give an example.
aggregation - 68
What is database normalization, and why is it useful?
databasenormalization - 69
What is a transaction, and what do the ACID properties guarantee?
transactionsacid - 70
What is SQL injection, and how do you prevent it?
sqlinjection - 71
What is the difference between WHERE and HAVING?
queriesaggregation - 72
When would you add an index to a table, and what does an index cost?
indexes - 73
Why does the condition column = NULL never match anything in SQL, and what should you use instead?
sqlschemafundamentals - 74
How would you find duplicate rows in a table using SQL?
dedupsql - 75
What happens when you type a URL into a browser and press Enter?
http - 76
What are the most common HTTP methods, and which of them are idempotent?
httpidempotency - 77
What do the HTTP status code classes 2xx, 3xx, 4xx, and 5xx mean?
httpstatus-codes - 78
What is the difference between HTTP and HTTPS?
httphttps - 79
What is an API, and what makes an API RESTful?
rest - 80
Why has JSON become the default data exchange format for web APIs?
api - 81
What are cookies, and what are they typically used for?
cookies - 82
What is DNS, and what happens during a DNS lookup?
dns - 83
Your code works locally but fails in CI. How do you investigate?
debugging - 84
You join a large unfamiliar codebase and need to add a feature. How do you approach it?
learningjoins - 85
What do you look for when reviewing someone else's pull request?
code-review - 86
A function in your service is slow. How do you find out why before optimizing?
optimization - 87
You need functionality that a third-party library provides. How do you decide between using the library and writing it yourself?
decision-makingdependencies - 88
Why does naming matter, and how do you pick good names for variables and functions?
clean-code - 89
What do you check before pushing your code for review?
code-review - 90
You receive a task with unclear requirements. What do you do before writing code?
requirements - 91
Tell me about a challenging bug you fixed. How did you track it down and what did you learn?
story - 92
How do you react when a code review points out serious problems in your work?
code-reviewreact - 93
You have been stuck on a task for several hours. When and how do you ask for help?
problem-solving - 94
How do you prioritize when several tasks all seem urgent?
prioritization - 95
Tell me about a time you broke something. How did you handle it?
story - 96
How do you approach learning a technology you have never used?
learning - 97
How do you estimate a task you have never done before?
estimation - 98
You disagree with a teammate's technical approach. What do you do?
conflict - 99
What does it mean for a task to be done, beyond the code compiling?
definition-of-done - 100
How do you explain a technical problem to a non-technical person?
communication