Software Engineer Interview Questions & Answers
This comprehensive guide covers the most frequently asked questions in software engineering interviews, from foundational concepts to advanced system design.
Technical Fundamentals
Q1: What is the difference between a process and a thread?
A process is an independent program in execution with its own memory space. A thread is a lightweight unit of execution within a process that shares the process's memory space.
Key differences: Processes are isolated and don't share memory, making them more secure but slower to communicate. Threads within the same process share memory, enabling faster communication but requiring careful synchronization to avoid race conditions.
Use processes when you need isolation (like running separate applications). Use threads when you need concurrency within an application (like handling multiple user requests).
Q2: Explain the SOLID principles.
SOLID is an acronym for five object-oriented design principles:
Single Responsibility Principle: A class should have only one reason to change. Each class should do one thing well.
Open/Closed Principle: Software entities should be open for extension but closed for modification. Add new functionality by extending, not changing existing code.
Liskov Substitution Principle: Objects of a superclass should be replaceable with objects of its subclasses without breaking the application.
Interface Segregation Principle: Many specific interfaces are better than one general-purpose interface. Clients shouldn't depend on methods they don't use.
Dependency Inversion Principle: High-level modules shouldn't depend on low-level modules. Both should depend on abstractions.
Q3: What is the difference between SQL and NoSQL databases?
SQL databases are relational, using structured tables with predefined schemas. They excel at complex queries, transactions, and maintaining data integrity through ACID compliance. Examples: PostgreSQL, MySQL.
NoSQL databases are non-relational and schema-flexible. They're designed for scalability and handling unstructured or semi-structured data. Types include document stores (MongoDB), key-value stores (Redis), column-family (Cassandra), and graph databases (Neo4j).
Choose SQL when you need complex joins, transactions, and data consistency. Choose NoSQL when you need horizontal scalability, flexible schemas, or are working with document/graph data.
Q4: What is RESTful API design?
REST (Representational State Transfer) is an architectural style for designing networked applications. Key principles include:
Statelessness: Each request contains all information needed; the server doesn't store client state between requests.
Resource-based URLs: URLs identify resources (nouns, not verbs). Example: /users/123, not /getUser?id=123.
HTTP methods for actions: GET (read), POST (create), PUT/PATCH (update), DELETE (remove).
Standard status codes: 200 (success), 201 (created), 400 (bad request), 404 (not found), 500 (server error).
Q5: Explain CAP theorem.
CAP theorem states that a distributed system can only guarantee two of three properties simultaneously:
Consistency: All nodes see the same data at the same time.
Availability: Every request receives a response (success or failure).
Partition Tolerance: The system continues operating despite network partitions.
In practice, partition tolerance is required for distributed systems, so you choose between consistency (CP systems like MongoDB, HBase) and availability (AP systems like Cassandra, CouchDB).
Data Structures & Algorithms
Q6: What is the time complexity of common operations in a hash table?
Average case: O(1) for insert, lookup, and delete operations.
Worst case: O(n) when many collisions occur and all elements hash to the same bucket.
Hash tables achieve O(1) average by using a hash function to compute an index directly. Collisions are handled through chaining (linked lists at each bucket) or open addressing (probing for empty slots).
Q7: When would you use a tree vs. a hash table?
Use a hash table when you need O(1) average lookup by key and don't need ordered traversal.
Use a balanced tree (like Red-Black or AVL) when you need ordered data, range queries, or guaranteed O(log n) operations. Trees also use memory more predictably and handle poor hash functions gracefully.
Use a tree when: finding min/max, range queries, ordered iteration, or worst-case guarantees matter.
Q8: Explain how a B-tree works and where it's used.
A B-tree is a self-balancing tree where nodes can have multiple keys and children. Properties include: all leaves at the same depth, nodes have minimum/maximum key limits, and keys within nodes are sorted.
B-trees minimize disk I/O by having high branching factors, keeping trees shallow. With thousands of keys per node, even billions of records require only 3-4 levels.
Used extensively in databases and file systems (PostgreSQL, MySQL, NTFS, ext4) where data resides on disk and minimizing reads is critical.
Q9: What is dynamic programming?
Dynamic programming solves complex problems by breaking them into overlapping subproblems, solving each once, and storing results.
Two approaches: Top-down (memoization) uses recursion with caching. Bottom-up (tabulation) builds solutions iteratively from smallest subproblems.
Classic examples: Fibonacci sequence, longest common subsequence, knapsack problem, edit distance.
When to use: optimal substructure (optimal solution contains optimal solutions to subproblems) and overlapping subproblems (same subproblems solved multiple times).
Q10: Explain graph traversal algorithms (BFS vs DFS).
BFS (Breadth-First Search) explores all neighbors at the current depth before moving deeper. Uses a queue. Finds shortest path in unweighted graphs. Memory: O(width of graph).
DFS (Depth-First Search) explores as far as possible along each branch before backtracking. Uses a stack (or recursion). Good for detecting cycles, topological sorting. Memory: O(depth of graph).
Choose BFS for shortest path problems. Choose DFS for exhaustive search, cycle detection, or when memory is constrained.
System Design
Q11: How would you design a URL shortening service like bit.ly?
Key components:
Requirements: Generate short URLs, redirect to original, handle high read traffic, analytics (optional).
URL generation: Base62 encoding of auto-incrementing ID or hash-based approach. 7-character base62 string handles 3.5 trillion URLs.
Storage: Key-value store (short URL → original URL). Redis for hot cache, persistent store for durability.
Scaling: Stateless servers behind load balancer. Read-heavy workload suits caching. Partition data by URL prefix or hash.
Trade-offs: Predictable IDs (sequential) vs. random (hash-based). Custom short URLs add complexity.
Q12: Design a rate limiter.
Algorithms:
Token Bucket: Tokens added at fixed rate, request consumes token. Allows bursts up to bucket capacity.
Leaky Bucket: Requests enter bucket, processed at fixed rate. Smooths traffic but delays bursts.
Fixed Window: Count requests per time window. Simple but allows double the limit at window boundaries.
Sliding Window Log: Store timestamp of each request. Precise but memory-intensive.
Sliding Window Counter: Hybrid approach. Weighted sum of current and previous window.
Implementation: Redis with INCR and EXPIRE, or in-memory for single-server.
Q13: How would you design a distributed cache?
Key considerations:
Partitioning: Consistent hashing distributes keys across nodes, minimizing redistribution when nodes change.
Replication: Write to multiple nodes for durability. Trade-off between consistency and availability.
Eviction policies: LRU (least recently used), LFU (least frequently used), TTL (time to live).
Cache invalidation: Write-through (synchronous write to cache and DB), write-behind (async write to DB), cache-aside (application manages cache).
Handling failures: Replicas, fallback to database, circuit breakers.
Example: Redis Cluster with consistent hashing, master-replica pairs per shard.
Coding Patterns
Q14: Explain the two-pointer technique.
Two pointers is a pattern where two indices traverse a data structure, typically from opposite ends or at different speeds.
Common uses: Finding pairs with a target sum in sorted array, removing duplicates, detecting cycles in linked lists (fast/slow pointers), reversing arrays.
Example problem: Given sorted array, find two numbers that sum to target.
Start with left pointer at beginning, right at end. If sum is too small, move left right. If too large, move right left. O(n) time, O(1) space.
Q15: When do you use recursion vs iteration?
Use recursion when the problem has a natural recursive structure (trees, graphs, divide-and-conquer), when code clarity matters more than performance, or when working with inherently recursive data structures.
Use iteration when you need to avoid stack overflow on deep recursion, when performance is critical (iteration avoids function call overhead), or when the iterative solution is equally clear.
Many recursive solutions can be converted to iteration using an explicit stack.
Q16: What is backtracking?
Backtracking is a recursive algorithm that builds solutions incrementally, abandoning ("backtracking") a solution as soon as it determines the solution cannot be completed.
Used for: N-Queens, Sudoku solver, generating permutations/combinations, maze solving.
Pattern: Make a choice, recurse to explore, undo the choice (backtrack), try next option.
Key optimization: Prune search space early when partial solution is invalid.
Behavioral & Soft Skills
Q17: Tell me about a challenging bug you solved.
Structure your answer using STAR: Describe the Situation (context, impact), Task (your responsibility), Actions (debugging process, tools used, how you identified root cause), and Result (fix, prevention measures, lessons learned).
Emphasize systematic debugging approach: reproducing the issue, forming hypotheses, testing them, narrowing down the cause. Mention tools used (debuggers, logs, profilers).
Q18: How do you handle disagreements with team members?
Demonstrate emotional intelligence: Listen to understand their perspective fully before advocating for yours. Focus on shared goals and data rather than personal preferences.
Show flexibility: Willingness to be wrong and change your mind with new information. Distinguish between "disagree and commit" (supporting team decision once made) vs. continuing to advocate when you believe the decision is harmful.
Q19: How do you prioritize when everything is urgent?
Discuss your framework: Evaluate actual impact and urgency vs. perceived urgency. Communicate trade-offs to stakeholders. Break large tasks into smaller deliverables.
Show initiative: Proactive communication when you can't meet all deadlines. Suggesting process improvements to prevent future fire drills.
Q20: Describe a time you improved a process or system.
Show ownership and initiative: Identify problems proactively, not just when assigned. Propose and implement solutions. Measure impact.
Emphasize collaboration: Getting buy-in from stakeholders, working with team to implement changes, documenting for future reference.
This guide covers essential questions across software engineering interviews. Remember that interviewers want to see your problem-solving process, not just final answers. Practice explaining your thought process clearly, ask clarifying questions, and don't be afraid to think out loud.
