Back to Categories
CS Fundamentals

CS Fundamentals

Big O, data structures, algorithms, browser internals and HTTP

24Questions

🧠 Simple Definition (Word-for-word)

Big O describes how runtime scales with input size.


⚡ Super Simple Line

Common complexities: O(1) constant — object property access, Map/Set get/has/add; O(n) linear — array forEach/map/filter, indexOf; O(log n) — binary search on sorted array; O(n log n) — Array.sort(); O(n^2) — nested loops.


⚡ Key Details & Explanation

Big O describes how runtime scales with input size. Common complexities: O(1) constant — object property access, Map/Set get/has/add; O(n) linear — array forEach/map/filter, indexOf; O(log n) — binary search on sorted array; O(n log n) — Array.sort(); O(n^2) — nested loops. Space complexity similarly. In interviews: always state the complexity of your solution and why. Interviewer wants to hear 'this is O(n) time and O(1) space because...'.


🌱 Beginner Explanation

Big O is not exact runtime in seconds. It tells how fast work grows when input grows.

Example:

  • O(1): does same amount of work no matter input size

  • O(n): if input doubles, work roughly doubles

  • O(n^2): if input doubles, work grows much faster

Interviewers usually want two things: your approach and your time/space complexity.


🗣️ How To Explain In Interview

Big O describes how an algorithm scales as input size grows. For example, a single loop is usually O(n), nested loops are often O(n^2), and binary search is O(log n). In interviews, I always mention both time and space complexity and explain why.


❓ Follow-up Questions

  • Why ignore constants in Big O?
    Because Big O focuses on growth trend, not exact runtime.

  • What is space complexity?
    How memory usage grows with input size.

  • Is O(1) always fast?
    Usually, but constants and real hardware still matter in practice.

🧠 Simple Definition (Word-for-word)

A stack is LIFO: last in, first out.


⚡ Super Simple Line

Operations are push and pop.


⚡ Key Details & Explanation

A stack is LIFO: last in, first out. Operations are push and pop. Common uses: function call stack, undo history, DFS. A queue is FIFO: first in, first out. Operations are enqueue and dequeue. Common uses: task scheduling, BFS, message processing. Interviewers often care less about memorizing names and more about whether you can map the right structure to the right problem.


🌱 Beginner Explanation

Stack and queue are both linear data structures, but order is different.

  • Stack: last in, first out

  • Queue: first in, first out

Memory trick:

  • Stack = pile of plates

  • Queue = line of people


🗣️ How To Explain In Interview

A stack is LIFO, so the most recently added element comes out first. A queue is FIFO, so the earliest added element comes out first. Stacks are common in recursion, undo history, and DFS, while queues are common in scheduling, BFS, and message processing.


❓ Follow-up Questions

  • Which data structure does BFS use?
    Queue.

  • Which data structure does DFS often use?
    Stack or recursion.

  • What are core stack operations?
    Push and pop.

🧠 Simple Definition (Word-for-word)

Choose recursion when the problem is naturally recursive, such as tree traversal or divide-and-conquer, and the depth is safe.


⚡ Super Simple Line

Choose iteration when you want tighter control over memory, avoid call-stack limits, or process large inputs reliably.


⚡ Key Details & Explanation

Choose recursion when the problem is naturally recursive, such as tree traversal or divide-and-conquer, and the depth is safe. Choose iteration when you want tighter control over memory, avoid call-stack limits, or process large inputs reliably. Recursive code can be cleaner; iterative code is often safer in production JavaScript because deep recursion can overflow the stack.


🌱 Beginner Explanation

Recursion means function calls itself. Iteration means loop-based solution.

Choose based on:

  • How naturally problem fits recursive structure

  • How deep recursion may go

  • Memory and stack safety requirements


🗣️ How To Explain In Interview

I choose recursion when the problem is naturally hierarchical, like trees or divide-and-conquer. I choose iteration when I want more control over memory and need to avoid call stack limits. In JavaScript, iteration is often safer for very large input because recursion can overflow the stack.


❓ Follow-up Questions

  • Example where recursion is natural?
    Tree traversal.

  • Example where iteration is safer?
    Very large linked list or deeply nested structure.

  • Why can recursion fail in JS?
    Call stack depth is limited.

🧠 Simple Definition (Word-for-word)

Recursive: function flatten(arr) { return arr.reduce((acc, val) => Array.isArray(val) ?


⚡ Super Simple Line

acc.concat(flatten(val)) : [...acc, val], []); } Iterative (stack-based, avoids stack overflow for deeply nested): function flatten(arr) { const stack = [...arr]; const result = []; while (stack.length) { const item = stack.pop(); if (Array.isArray(item)) stack.push(...item); else result.push(item); } return result.reverse(); } This matters because computer science fundamentals help explain why one solution is faster, safer, or more reliable than another.


🌱 Beginner Explanation

Flattening means turning nested arrays into one single array.

[1, [2, [3, 4]], 5] becomes [1, 2, 3, 4, 5]

Recursive solution matches nested structure naturally. Iterative stack solution is safer for very deep nesting.


🗣️ How To Explain In Interview

I can solve this recursively by saying: if value is an array, flatten it and merge it; otherwise push value directly. That is clean and easy to explain. If I want to avoid call stack risk for deeply nested arrays, I can use an explicit stack iteratively instead.


❓ Follow-up Questions

  • Why reverse result in stack solution?
    Because stack pops in reverse order.

  • Why prefer iterative sometimes?
    To avoid recursion depth issues.

  • What is time complexity?
    O(n) where n is total number of elements visited.

🧠 Simple Definition (Word-for-word)

Naive: nested loops O(n^2).


⚡ Super Simple Line

Optimal O(n) with a hash set: const seen = new Set(); for (const num of nums) { const complement = target - num; if (seen.has(complement)) return [complement, num]; seen.add(num); } — One pass, O(n) time, O(n) space.


⚡ Key Details & Explanation

Naive: nested loops O(n^2). Optimal O(n) with a hash set: const seen = new Set(); for (const num of nums) { const complement = target - num; if (seen.has(complement)) return [complement, num]; seen.add(num); } — One pass, O(n) time, O(n) space. For sorted array: two pointers O(n) time O(1) space — start at both ends, move inward based on sum vs target.


🌱 Beginner Explanation

Goal is to find two numbers whose sum equals target. Brute force checks every pair. Better idea: while scanning array, remember numbers already seen.

If target is 10 and current number is 3, I ask: have I already seen 7?

If yes, answer found.


🗣️ How To Explain In Interview

I would use a hash set or hash map for O(1) average lookup. For each number, I compute the complement as target minus current number. If the complement is already in the set, I found the pair. Otherwise I store the current number and continue. That gives O(n) time and O(n) space.


❓ Follow-up Questions

  • Why is brute force O(n^2)?
    Because it checks pairs with nested loops.

  • When can two pointers be used?
    When array is sorted.

  • Hash set or hash map?
    Set for values, map if interviewer wants original indices too.

🧠 Simple Definition (Word-for-word)

Iterative: let prev = null, curr = head; while (curr) { let next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; — O(n) time, O(1) space.


⚡ Super Simple Line

Recursive: function reverse(node, prev=null) { if (!node) return prev; let next = node.next; node.next = prev; return reverse(next, node); } — O(n) time, O(n) space (call stack).


⚡ Key Details & Explanation

Iterative: let prev = null, curr = head; while (curr) { let next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; — O(n) time, O(1) space. Recursive: function reverse(node, prev=null) { if (!node) return prev; let next = node.next; node.next = prev; return reverse(next, node); } — O(n) time, O(n) space (call stack). Iterative is preferred for large lists (no stack overflow risk).


🌱 Beginner Explanation

Linked list reversal means changing arrow direction of every node.

1 -> 2 -> 3 -> null becomes 3 -> 2 -> 1 -> null

Main challenge: before changing curr.next, save original next node or you lose rest of list.


🗣️ How To Explain In Interview

I keep three pointers: previous, current, and next. For each node, I save next, reverse the pointer, move previous forward, then move current forward. Iterative solution is O(n) time and O(1) space, so it is usually preferred over recursion.


❓ Follow-up Questions

  • Why save next first?
    Because after reversing pointer, original next would be lost.

  • Why is recursion O(n) space?
    Because of call stack frames.

  • Which version is safer in JS?
    Iterative, because deep recursion can overflow stack.

🧠 Simple Definition (Word-for-word)

A collision happens when two keys map to the same bucket or index.


⚡ Super Simple Line

Common strategies: separate chaining, where each bucket stores a list of entries, and open addressing, where the table probes for another empty slot.


⚡ Key Details & Explanation

A collision happens when two keys map to the same bucket or index. Common strategies: separate chaining, where each bucket stores a list of entries, and open addressing, where the table probes for another empty slot. Good hash functions and resizing keep average operations near O(1), but worst case can degrade if collisions are excessive. In real systems, load factor and resize policy matter a lot.


🌱 Beginner Explanation

A hash function turns a key into an index. Collision happens when different keys produce same bucket/index.

This does not mean hash table is broken. It means it needs a strategy to store both values safely.


🗣️ How To Explain In Interview

Hash table collisions happen when two keys map to the same location. Common strategies are separate chaining, where each bucket stores a list of entries, and open addressing, where the table probes for another available slot. With a good hash function and proper resizing, average lookup stays near O(1).


❓ Follow-up Questions

  • What is load factor?
    How full hash table is.

  • Why resize hash table?
    To reduce collisions and maintain fast average operations.

  • Worst-case complexity?
    Can degrade toward O(n) with many collisions.

🧠 Simple Definition (Word-for-word)

BST: left subtree < node < right subtree.


⚡ Super Simple Line

Insert: compare with current node, go left if smaller, right if larger, insert when null.


⚡ Key Details & Explanation

BST: left subtree < node < right subtree. Insert: compare with current node, go left if smaller, right if larger, insert when null. Search: same traversal, return true when found. class Node { constructor(val) { this.val=val; this.left=this.right=null; } } insert: if (!root) return new Node(val); if (val < root.val) root.left = insert(root.left, val); else root.right = insert(root.right, val); return root. Worst case O(n) for unbalanced tree; O(log n) balanced.


🌱 Beginner Explanation

A Binary Search Tree keeps values ordered.

left < node < right

This ordering makes search efficient in balanced trees because each comparison removes about half the remaining tree, similar idea to binary search on arrays.


🗣️ How To Explain In Interview

A BST is a binary tree where all values in the left subtree are smaller and all values in the right subtree are larger. Insert and search both work by comparing the target to the current node and moving left or right recursively or iteratively. Average complexity is O(log n) if the tree is balanced, but O(n) if it becomes skewed.


❓ Follow-up Questions

  • Why can BST become O(n)?
    If inserted values make it unbalanced like a linked list.

  • What fixes skewed trees?
    Self-balancing trees like AVL or Red-Black Tree.

  • Why not always use sorted array?
    Arrays are good for lookup, but inserts in middle are expensive.

🧠 Simple Definition (Word-for-word)

BFS (breadth-first): explores level by level using a queue.


⚡ Super Simple Line

Use for: shortest path in unweighted graph, finding closest nodes, level-order traversal.


⚡ Key Details & Explanation

BFS (breadth-first): explores level by level using a queue. Use for: shortest path in unweighted graph, finding closest nodes, level-order traversal. DFS (depth-first): explores as deep as possible using a stack/recursion. Use for: detecting cycles, topological sort, exploring all paths, tree traversals (inorder, preorder, postorder). BFS implementation: const visited = new Set(); const queue = [start]; visited.add(start); while (queue.length) { const node = queue.shift(); for (const neighbor of graph[node]) { if (!visited.has(neighbor)) { visited.add(neighbor); queue.push(neighbor); } } }


🌱 Beginner Explanation

BFS and DFS are both graph/tree traversal methods.

  • BFS explores neighbors first

  • DFS goes deep first

Easy memory trick:

  • BFS uses Queue

  • DFS uses Stack or recursion


🗣️ How To Explain In Interview

I use BFS when level-by-level traversal matters, especially shortest path in an unweighted graph. I use DFS when I want to explore full paths, detect cycles, or do recursive traversals. Main implementation difference is queue for BFS versus stack or recursion for DFS.


❓ Follow-up Questions

  • Which finds shortest path in unweighted graph?
    BFS.

  • Which is often easier recursively?
    DFS.

  • Why keep visited set?
    To avoid infinite loops in graphs with cycles.

🧠 Simple Definition (Word-for-word)

DP: break problem into overlapping subproblems, solve each once and store results.


⚡ Super Simple Line

Bottom-up coin change: given coins and amount, find minimum coins to make amount.


⚡ Key Details & Explanation

DP: break problem into overlapping subproblems, solve each once and store results. Bottom-up coin change: given coins and amount, find minimum coins to make amount. function coinChange(coins, amount) { const dp = new Array(amount+1).fill(Infinity); dp[0] = 0; for (let i=1; i<=amount; i++) { for (const coin of coins) { if (coin <= i) dp[i] = Math.min(dp[i], dp[i-coin]+1); } } return dp[amount]===Infinity ? -1 : dp[amount]; } O(amount * coins.length) time.


🌱 Beginner Explanation

Dynamic programming is useful when same small problem appears again and again.

Coin change example asks: minimum number of coins to make each amount from 0 to target. Instead of solving same subproblems repeatedly, store answers in an array.

That is core DP idea: save past results and reuse them.


🗣️ How To Explain In Interview

Dynamic programming works when a problem has overlapping subproblems and optimal substructure. In coin change, I compute the minimum coins needed for every amount from 0 to target and build the final answer from previously solved smaller amounts. That avoids repeated work and gives a bottom-up solution.


❓ Follow-up Questions

  • What are overlapping subproblems?
    Same smaller problems appear multiple times.

  • Top-down or bottom-up?
    Both are DP styles; top-down uses memoization, bottom-up uses tabulation.

  • Why initialize dp with Infinity?
    It means amount is not reachable yet.

🧠 Simple Definition (Word-for-word)

LRU evicts the least recently accessed item when capacity is reached.


⚡ Super Simple Line

Optimal O(1) get and put: use a doubly linked list (order by recency) + HashMap (O(1) lookup).


⚡ Key Details & Explanation

LRU evicts the least recently accessed item when capacity is reached. Optimal O(1) get and put: use a doubly linked list (order by recency) + HashMap (O(1) lookup). Get: if key in map, move node to front, return value. Put: if key exists, update and move to front. If at capacity, remove the tail (LRU). Add new node to front. In JS: use Map (insertion-ordered) as a shortcut — Map maintains insertion order, so delete+re-insert moves to end, and map.keys().next() gets the oldest. This gives O(1) operations.


🌱 Beginner Explanation

LRU cache keeps recently used items and removes the oldest unused one when full.

Real-life analogy: desk with limited space. Most recently used documents stay near top; least used gets removed first.

Interviewer usually wants you to know why HashMap + Doubly Linked List gives O(1) operations.


🗣️ How To Explain In Interview

An LRU cache needs two things: fast lookup by key and fast updates to recency order. A hash map gives O(1) lookup, and a doubly linked list gives O(1) removal and insertion when an item becomes most recent or least recent. That combination gives O(1) get and put.


❓ Follow-up Questions

  • Why not array only?
    Because moving items in arrays is not O(1).

  • What does get do besides return value?
    It also marks item as most recently used.

  • What gets evicted?
    Least recently used item, usually tail of linked list.

🧠 Simple Definition (Word-for-word)

Object-Oriented Programming (OOP) is a programming paradigm that organizes code around objects, which are instances of classes.


⚡ Super Simple Line

The core principles of OOP are: Encapsulation: Bundling data and methods that operate on that data within a single unit (class).


⚡ Key Details & Explanation

  • Encapsulation: Bundling data and methods that operate on that data within a single unit (class).
  • Inheritance: Creating new classes based on existing ones to promote code reusability.
  • Polymorphism: Allowing objects of different classes to be treated as objects of a common superclass, typically through method overriding.
  • Abstraction: Hiding complex implementation details and exposing only the necessary features to the user.

These principles help in creating modular, reusable, and maintainable code.


🌱 Beginner Explanation

OOP organizes code around objects that combine data and behavior.

Instead of only writing loose functions, you can model things like User, Order, or Car with properties and methods.


🗣️ How To Explain In Interview

OOP is a programming style where code is organized around objects and classes. Its core ideas are encapsulation, inheritance, polymorphism, and abstraction. The goal is to build modular, reusable, and maintainable systems by grouping related data and behavior together.


❓ Follow-up Questions

  • What is encapsulation?
    Bundling data and methods together with controlled access.

  • What is polymorphism?
    Different objects can respond to same method name in their own way.

  • Is OOP always best?
    No. Sometimes functional or simpler procedural style is better.

🧠 Simple Definition (Word-for-word)

Abstraction means hiding complex implementation details and exposing only what’s necessary.


🌱 Beginner Explanation

Abstraction means showing only useful interface and hiding internal complexity.

Example: you drive a car with steering wheel and pedals. You do not need to know exact engine internals each time you drive.


🗣️ How To Explain In Interview

Abstraction means hiding implementation details and exposing only the operations a user of the code needs. It simplifies complex systems because callers can use a clear interface without understanding every internal step.


❓ Follow-up Questions

  • How is abstraction different from encapsulation?
    Abstraction hides complexity; encapsulation bundles data and behavior together and controls access.

  • Why is abstraction useful?
    It reduces cognitive load and improves maintainability.

  • Example in code?
    A service method hides database query details from callers.

🧠 Simple Definition (Word-for-word)

Method Overloading is when you have multiple methods with the same name but different parameters (not supported in JavaScript).


⚡ Super Simple Line

Method Overriding is when a subclass provides a specific implementation of a method that is already defined in its superclass.


⚡ Key Details & Explanation

  • Method Overloading is when you have multiple methods with the same name but different parameters (not supported in JavaScript).
  • Method Overriding is when a subclass provides a specific implementation of a method that is already defined in its superclass.

🌱 Beginner Explanation

Overloading and overriding sound similar but are different.

  • Overloading: same method name, different parameter list

  • Overriding: child class changes inherited behavior

Important JS note: JavaScript does not support traditional compile-time method overloading like Java or C++.


🗣️ How To Explain In Interview

Method overloading means methods share the same name but differ by parameters, though JavaScript does not support this in the traditional OOP sense. Method overriding means a subclass provides its own implementation of a method defined in the parent class.


❓ Follow-up Questions

  • Which one needs inheritance?
    Overriding.

  • Can JS mimic overloading?
    Yes, by checking arguments manually inside one function.

  • Why override methods?
    To customize inherited behavior.

🧠 Simple Definition (Word-for-word)

SOLID is a set of design principles that help write clean and maintainable code.


⚡ Super Simple Line

Single Responsibility → one class should have one responsibility Open/Closed → open for extension, closed for modification Liskov Substitution → child classes should behave like parent Interface Segregation → don’t force classes to implement unused methods Dependency Inversion → depend on abstractions, not concrete implementations


⚡ Key Details & Explanation

  • Single Responsibility → one class should have one responsibility
  • Open/Closed → open for extension, closed for modification
  • Liskov Substitution → child classes should behave like parent
  • Interface Segregation → don’t force classes to implement unused methods
  • Dependency Inversion → depend on abstractions, not concrete implementations

🌱 Beginner Explanation

SOLID is not about memorizing letters only. It is about making code easier to change without breaking everything.

Best beginner way: know one simple sentence for each principle and one tiny example.


🗣️ How To Explain In Interview

SOLID is a set of object-oriented design principles for maintainable code. Single Responsibility means one unit should have one reason to change. Open/Closed means extend behavior without modifying stable code. Liskov Substitution means child types should behave correctly where parent types are expected. Interface Segregation means small focused interfaces are better than large ones. Dependency Inversion means depend on abstractions instead of concrete implementations.


❓ Follow-up Questions

  • Which principle is most commonly violated?
    Single Responsibility is very commonly violated.

  • Why depend on abstractions?
    It reduces coupling and improves testability.

  • Why keep interfaces small?
    So consumers implement only what they actually need.

🧠 Simple Definition (Word-for-word)

An Operating System Kernel is the core computer program at the heart of an OS, possessing complete control over everything in the system. It acts as a bridge between application software and physical computer hardware, managing system resources. Its key responsibilities are: Memory management, Process scheduling, Device driver communication, and System calls.


⚡ Super Simple Line

Kernel = the core translator and controller that connects software apps to physical CPU, RAM, and hardware.


📋 Core Responsibilities

  • Process Management: Allocates CPU execution time to different running programs (processes) using schedulers.

  • Memory Management: Keeps track of physical RAM allocations, virtual memory address mapping, and prevents processes from overwriting each other's memory.

  • Device Management: Acts as an intermediary between hardware peripherals (disks, keyboards, GPUs) and applications using device drivers.

  • System Calls: Exposes secure APIs (like file reading or socket creation) to user applications since they cannot access hardware directly.


⚡ One-line Interview Answer

The kernel is the foundational core of an operating system that manages hardware resources, processes scheduling, and memory allocation while exposing secure system call APIs to applications.


🌱 Beginner Explanation

The kernel is core part of operating system that directly controls hardware resources.

User applications cannot freely talk to CPU, disk, or memory hardware. Kernel sits in middle and provides safe controlled access through system calls.


🗣️ How To Explain In Interview

The kernel is the core of the operating system. It manages CPU scheduling, memory, devices, and secure access to hardware through system calls. It is important because it is the layer that lets applications use hardware safely and efficiently.


❓ Follow-up Questions

  • What is a system call?
    A controlled request from user program to kernel.

  • Why can't apps access hardware directly?
    For safety, isolation, and resource management.

  • What does scheduler do?
    Decides which process/thread gets CPU time.

🧠 Simple Definition

Stack memory stores function call frames and local execution context. Heap memory stores dynamically allocated data like objects, arrays, and structures that need longer or flexible lifetime.


⚡ Super Simple Line

Stack = call history and local context.
Heap = larger dynamic data storage.


⚡ Key Details & Explanation

Stack memory is usually very fast and organized in LIFO order, which fits function calls naturally. Heap memory is more flexible, but allocation and cleanup are more complex. In JavaScript terms, call stack is where functions run, while objects and arrays live in heap and are managed by garbage collection.

Simple mental model:

  • Stack: the functions running right now
  • Heap: data those functions are working with


🗣️ How To Explain In Interview

Stack memory is used for function calls and local execution context, while heap memory stores dynamically allocated data such as objects and arrays. Stack access is fast and structured, while heap is more flexible but needs memory management like garbage collection.


❓ Follow-up Questions

  • Why can recursion overflow stack?
    Because each recursive call adds a new stack frame.

  • Where do JS objects live?
    In heap memory.

  • Why is heap harder to manage?
    Because object lifetimes are dynamic and not simple push/pop order.


✅ Final Memory Line

Stack runs functions. Heap stores dynamic data.

🧠 Simple Definition

A process is an independent running program with its own memory space. A thread is a smaller execution unit inside a process, and threads within the same process share memory.


⚡ Super Simple Line

Process = separate app container.
Thread = worker inside that container.


⚡ Key Details & Explanation

If you open browser and code editor, those are usually separate processes. Inside browser process, many threads may work at same time for rendering, networking, and other tasks. Processes are safer because memory is isolated. Threads are lighter and faster to create, but sharing memory means synchronization problems can happen.

Important difference:

  • Process crash usually does not directly crash another process

  • Thread crash can affect whole process


🗣️ How To Explain In Interview

A process is an isolated running program with its own memory, while a thread is an execution path inside a process that shares memory with other threads in that same process. Processes give stronger isolation, while threads are lighter and better for concurrent work inside one application.


❓ Follow-up Questions

  • Why are threads faster to create?
    Because they share process resources instead of getting a full new memory space.

  • Why are processes safer?
    Because memory isolation prevents one process from directly corrupting another.

  • Why are threads harder?
    Because shared memory can cause race conditions.


✅ Final Memory Line

Process = isolated program. Thread = lightweight worker inside process.

🧠 Simple Definition

A race condition happens when the correctness of a program depends on the timing or order of multiple operations, and different execution orders can produce wrong results.


⚡ Super Simple Line

Race condition = two things run at same time and interfere.


⚡ Key Details & Explanation

Classic example: two requests read same bank balance of 100, both subtract 80, and both write back 20. One update gets lost because the operations were not coordinated correctly.

Common prevention methods:

  • Locks or mutexes

  • Atomic database operations

  • Transactions

  • Unique constraints

  • Immutability and message queues in some designs

Main idea is to make shared updates happen safely.


🗣️ How To Explain In Interview

A race condition occurs when multiple operations access shared state concurrently and the result depends on execution timing. I prevent it by using synchronization techniques like locks, atomic operations, transactions, or database constraints, depending on where the shared state lives.


❓ Follow-up Questions

  • Why are threads risky here?
    Because they share memory.

  • Can databases have race conditions too?
    Yes, especially under concurrent writes.

  • What is an atomic operation?
    An operation that happens as one indivisible step.


✅ Final Memory Line

Race condition = wrong result caused by unsafe concurrent access to shared state.

🧠 Simple Definition

TCP is a reliable, connection-oriented transport protocol. UDP is a faster, connectionless transport protocol that does not guarantee delivery, order, or duplicate protection.


⚡ Super Simple Line

TCP = reliable but heavier.
UDP = fast but no guarantees.


⚡ Key Details & Explanation

TCP establishes a connection first and then sends data with acknowledgements, retries, and ordering. That makes it good for correctness. UDP sends packets without that overhead, which makes it faster and useful when speed matters more than perfect reliability.

Examples:

  • TCP: HTTP/1.1, HTTP/2, database connections, email

  • UDP: live video, online gaming, DNS queries, QUIC foundation for HTTP/3


🗣️ How To Explain In Interview

TCP is connection-oriented and guarantees ordered reliable delivery, so it is used when correctness matters. UDP is connectionless and avoids delivery guarantees, so it is useful for low-latency scenarios where losing some packets is acceptable.


❓ Follow-up Questions

  • Why is TCP slower?
    Because it does handshakes, acknowledgements, retries, and ordering.

  • Why use UDP for video calls?
    Because low latency matters more than resending every lost packet.

  • Does HTTP/3 use TCP?
    No, it uses QUIC over UDP.


✅ Final Memory Line

TCP gives guarantees. UDP gives speed.

🧠 Simple Definition

DNS, or Domain Name System, translates human-readable domain names like google.com into IP addresses like 142.250.x.x that computers use to communicate.


⚡ Super Simple Line

DNS = internet phonebook.


⚡ Key Details & Explanation

When you type a domain, the browser first checks local caches. If not found, a resolver queries DNS servers step by step until it finds the authoritative answer.

Simple resolution flow:

  1. Browser cache check

  2. OS cache check

  3. DNS resolver asked

  4. Resolver may query root server

  5. Then TLD server like .com

  6. Then authoritative name server for domain

  7. Final IP returned to client

That IP is then used for the actual network connection.


🗣️ How To Explain In Interview

DNS is the naming system that maps domains to IP addresses. During DNS resolution, the browser and OS first check caches, then a recursive resolver queries the DNS hierarchy until it finds the authoritative record and returns the IP address needed to connect to the server.


❓ Follow-up Questions

  • Why cache DNS?
    To reduce lookup latency and DNS traffic.

  • What is a TLD server?
    A server responsible for top-level domains like .com or .org.

  • What comes after DNS resolution?
    TCP or QUIC connection to resolved IP.


✅ Final Memory Line

DNS turns domain names into IP addresses through cache checks and hierarchical lookup.

🧠 Simple Definition (Word-for-word)

Browser checks DNS cache, then OS cache, then DNS resolver → gets IP address.


⚡ Key Details & Explanation

  1. Browser checks DNS cache, then OS cache, then DNS resolver → gets IP address. 2. TCP handshake with the server (3-way: SYN, SYN-ACK, ACK). 3. TLS handshake for HTTPS (negotiates cipher, exchanges certificates, establishes encrypted channel). 4. HTTP GET request sent. 5. Server processes request, sends HTTP response with HTML. 6. Browser parses HTML, constructs DOM. 7. Encounters CSS → fetch, parse, construct CSSOM. 8. Encounter JS → fetch, parse, execute (may block parsing). 9. DOM + CSSOM → Render tree → Layout → Paint → Composite → Display.

🌱 Beginner Explanation

This question mixes networking, browser, and rendering basics.

Simple order to remember:

DNS -> TCP -> TLS -> HTTP -> HTML/CSS/JS -> Render

If you can say this sequence clearly, you already have a strong beginner answer.


🗣️ How To Explain In Interview

First the browser resolves the domain name to an IP address through DNS. Then it opens a TCP connection and, for HTTPS, performs a TLS handshake. After that it sends the HTTP request, receives the response, parses HTML, builds the DOM and CSSOM, executes JavaScript as needed, and finally the browser performs layout, paint, and compositing to display the page.


❓ Follow-up Questions

  • Why TLS handshake?
    To establish encrypted secure communication.

  • What is DOM?
    Browser's in-memory tree representation of HTML.

  • What can block rendering?
    CSS and parser-blocking JavaScript.

🧠 Simple Definition (Word-for-word)

HTTP/1.1: one request per TCP connection at a time (with keep-alive), text-based protocol, head-of-line blocking.


⚡ Super Simple Line

HTTP/2: binary protocol, multiplexing (multiple requests over one connection simultaneously), header compression (HPACK), server push, stream prioritization.


⚡ Key Details & Explanation

HTTP/1.1: one request per TCP connection at a time (with keep-alive), text-based protocol, head-of-line blocking. HTTP/2: binary protocol, multiplexing (multiple requests over one connection simultaneously), header compression (HPACK), server push, stream prioritization. HTTP/3: uses QUIC (UDP-based) instead of TCP — eliminates TCP head-of-line blocking, faster connection establishment (0-RTT reconnect), better performance on lossy networks (mobile). Vercel and Cloudflare support HTTP/3.


🌱 Beginner Explanation

HTTP/2 improved performance mainly by letting many requests share one connection.

Easy memory trick:

  • HTTP/1.1: many requests, more connection pain

  • HTTP/2: multiplexing on one TCP connection

  • HTTP/3: QUIC over UDP, better on unreliable networks


🗣️ How To Explain In Interview

HTTP/2 differs from HTTP/1.1 mainly by using a binary protocol with multiplexing and header compression, so multiple requests can travel on one connection efficiently. HTTP/3 goes further by using QUIC over UDP, which reduces connection setup time and improves behavior on lossy mobile networks.


❓ Follow-up Questions

  • What is multiplexing?
    Multiple streams share one connection at same time.

  • Why header compression?
    To reduce repeated header overhead.

  • Why is HTTP/3 better on mobile?
    QUIC handles packet loss and reconnection better.

🧠 Simple Definition (Word-for-word)

CRP: the sequence DOM → CSSOM → Render tree → Layout → Paint before first pixel appears.


⚡ Super Simple Line

CSS is render-blocking (browser won't paint until CSSOM is ready).


⚡ Key Details & Explanation

CRP: the sequence DOM → CSSOM → Render tree → Layout → Paint before first pixel appears. CSS is render-blocking (browser won't paint until CSSOM is ready). JS is parser-blocking by default (stops HTML parsing). Optimizations: async/defer scripts (defer maintains order, doesn't block parsing), inline critical CSS (above-the-fold styles), preload important resources, minimize CSS files, avoid large layout-causing JS on initial load, use font-display: swap for web fonts.


🌱 Beginner Explanation

Critical Rendering Path is browser work needed before user sees first meaningful pixels.

Main pipeline:

HTML -> DOM, CSS -> CSSOM, DOM + CSSOM -> Render Tree -> Layout -> Paint

Anything that delays these steps delays visible page rendering.


🗣️ How To Explain In Interview

The critical rendering path is the sequence the browser follows to convert HTML, CSS, and JavaScript into pixels on screen. To optimize it, I reduce render-blocking resources, defer noncritical JavaScript, inline critical CSS, preload important resources, and avoid heavy layout work during initial render.


❓ Follow-up Questions

  • Why is CSS render-blocking?
    Browser needs CSSOM before it can paint correctly.

  • What does defer do?
    Downloads script without blocking parsing and runs it after parsing.

  • What is layout?
    Calculating size and position of elements.