Back to Tech Interviews

Data Structures & Algorithms (DSA) Interview Questions

Master essential coding interview patterns, algorithm analysis, Big-O complexities, and data structure implementations

Total: 31 QuestionsLearned: 0 / 31 (0%)
Difficulty Filters

Tools & Options
Showing 31 of 31 questions
Beginner
What is Big-O Notation, and how do you calculate Time and Space Complexity?

Big-O notation describes the upper bound (worst-case scenario) of an algorithm's growth rate in terms of time (execution steps) or space (memory usage) relative to the input size N.

Key Complexity Levels:

1. O(1) Constant: Execution time stays constant regardless of N (e.g., array index lookup, hash table search).

2. O(log N) Logarithmic: Input is halved at each step (e.g., Binary Search, BST lookup).

3. O(N) Linear: Time grows proportionally with N (e.g., single loop, linear search).

4. O(N log N) Linearithmic: Efficient sorting algorithms (e.g., Merge Sort, Quick Sort).

5. O(N^2) Quadratic: Nested loops over input N (e.g., Bubble Sort, Matrix multiplication).

6. O(2^N) Exponential: Recursive algorithms solving subproblems independently (e.g., naive Fibonacci).

Space Complexity measures additional memory allocated during execution (excluding input storage). Stack space used by recursive call stacks is counted in auxiliary space.

// O(1) Constant Time
function getFirstElement(arr) {
  return arr[0]; 
}

// O(N) Linear Time
function findMax(arr) {
  let max = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] > max) max = arr[i];
  }
  return max;
}

// O(log N) Logarithmic Time - Binary Search
function binarySearch(arr, target) {
  let low = 0, high = arr.length - 1;
  while (low <= high) {
    let mid = Math.floor((low + high) / 2);
    if (arr[mid] === target) return mid;
    else if (arr[mid] < target) low = mid + 1;
    else high = mid - 1;
  }
  return -1;
}
Beginner
How are Arrays stored in memory? What is the difference between Static and Dynamic Arrays?

An Array is a collection of elements stored in contiguous (adjacent) memory locations. Because memory addresses are sequential, any element can be accessed in O(1) constant time using its base address and index formula: address = base_address + index * element_size.

Static Arrays:

- Fixed size allocated at initialization (e.g., in C/C++ or Java standard arrays).

- Memory reallocation is not possible; inserting beyond size causes index out of bounds error.

Dynamic Arrays (e.g., JavaScript Arrays, Python Lists, C++ std::vector):

- Automatically resizes when capacity is exceeded.

- When full, creates a new array with double capacity (usually 2x growth factor) and copies existing elements over.

- Amortized Time Complexity for insertion at end: O(1) average, O(N) worst-case during resize.

// Dynamic Array Resizing Concept
class DynamicArray {
  constructor() {
    this.capacity = 2;
    this.length = 0;
    this.data = new Array(this.capacity);
  }

  push(element) {
    if (this.length === this.capacity) {
      this._resize(this.capacity * 2); // Double capacity
    }
    this.data[this.length] = element;
    this.length++;
  }

  _resize(newCapacity) {
    const newData = new Array(newCapacity);
    for (let i = 0; i < this.length; i++) {
      newData[i] = this.data[i];
    }
    this.data = newData;
    this.capacity = newCapacity;
  }
}
Beginner
What is a Linked List? Compare Arrays vs Linked Lists and show how to Reverse a Linked List.

A Linked List is a linear data structure where elements (nodes) are stored non-contiguously in memory. Each node contains a data field and a pointer/reference (`next`) to the next node in the list.

Arrays vs Linked Lists Comparison:

- Access Time: Array is O(1) indexed access; Linked List is O(N) sequential traversal.

- Insertion/Deletion at head: Linked List is O(1) pointer updates; Array is O(N) element shifts.

- Insertion at middle/tail: Array is O(N); Linked List is O(1) if node reference is given, otherwise O(N) to traverse.

- Memory Overhead: Linked List uses extra memory for node pointers.

Reversing a Linked List iteratively requires three pointers: `prev`, `curr`, and `next`.

class ListNode {
  constructor(val = 0, next = null) {
    this.val = val;
    this.next = next;
  }
}

// Iterative Reversal - O(N) Time, O(1) Space
function reverseLinkedList(head) {
  let prev = null;
  let curr = head;

  while (curr !== null) {
    let nextNode = curr.next; // Store next node
    curr.next = prev;         // Reverse current pointer
    prev = curr;              // Move prev forward
    curr = nextNode;          // Move curr forward
  }

  return prev; // New head of reversed list
}
Beginner
Explain Stacks (LIFO) and Queues (FIFO). How do you solve the Valid Parentheses problem using a Stack?
Beginner
How does Binary Search work? What are its prerequisites and Time Complexity?
Beginner
Compare Insertion Sort, Selection Sort, and Bubble Sort. When is Insertion Sort preferred?
Intermediate
Explain the Two Pointers Pattern. How does it optimize Two Sum II (Sorted Array) from O(N^2) to O(N)?
Intermediate
What is the Sliding Window Pattern? Solve 'Maximum Sum Subarray of Size K' and 'Longest Substring Without Repeating Characters'.
Intermediate
Explain Kadane's Algorithm for Maximum Subarray Sum. What is its Time and Space Complexity?
Intermediate
How does Floyd's Cycle Detection Algorithm (Fast & Slow Pointers) detect a loop in a Linked List?
Intermediate
Design a Min Stack that supports push, pop, top, and getMin in O(1) time.
Intermediate
What is a Binary Search Tree (BST)? How do you validate if a Binary Tree is a valid BST?
Intermediate
Compare Tree Traversals: DFS (Preorder, Inorder, Postorder) vs BFS (Level-Order Traversal).
Intermediate
How do you find the Lowest Common Ancestor (LCA) of two nodes in a Binary Tree?
Intermediate
What is a Heap / Priority Queue? Explain Heapify and how to find the Kth Largest Element.
Intermediate
Compare Merge Sort vs Quick Sort in terms of Time, Space, and Stability.
Intermediate
Explain Graph Representations and Graph Traversals: BFS vs DFS.
Intermediate
What is a Trie (Prefix Tree)? Implement Insert, Search, and StartsWith operations.
Intermediate
Explain Bitwise Operations and Bit Tricks: Solve Single Number and Count Set Bits.
Advanced
Explain Dynamic Programming (DP) Principles: Memoization (Top-Down) vs Tabulation (Bottom-Up).
Advanced
Solve the 0/1 Knapsack Problem using Dynamic Programming.
Advanced
Explain the Longest Common Subsequence (LCS) Problem and its DP Solution.
Advanced
Solve the Coin Change Problem (Minimum Coins required for Amount) using DP.
Advanced
What is Topological Sort? Implement Kahn's Algorithm (BFS) for Dependency Scheduling.
Advanced
Explain Dijkstra's Algorithm for Shortest Path in Weighted Graphs.
Advanced
Explain Disjoint Set Union (DSU / Union-Find) with Path Compression and Union by Rank.
Advanced
What is a Monotonic Stack? Solve 'Next Greater Element' in O(N) time.
Scenario
Design an LRU (Least Recently Used) Cache with O(1) Get and Put operations.
Scenario
How do you find the Median in a Data Stream in O(log N) insert and O(1) findMedian?
Scenario
Solve the 3Sum Problem in O(N^2) Time using Sorting and Two Pointers.
Scenario
Solve Top K Frequent Elements using Bucket Sort in O(N) Time.

Technical Interview Mastery Blueprint

Proven methodologies and frameworks to succeed in technical and architecture rounds.

1. The Engineering STAR Technique

When responding to architectural or situational questions, structure your answer using Situation, Technical Constraint, Action, and Measurable Result. Rather than jumping straight to syntax, articulate the business problem, why certain patterns (e.g. caching, queuing, immutability) were selected over alternatives, and what latency or throughput improvements were achieved.

2. Defending Architectural Trade-Offs

Senior interviewers evaluate how you weigh trade-offs. Always explain why you chose an approach: e.g., memory overhead vs CPU cycle speed, consistency vs availability (CAP theorem), or normalized schemas vs denormalized fast reads. Stating the drawbacks of your own proposal demonstrates maturity and production experience.

3. Clean Code & Edge-Case Proactivity

In live-coding rounds, communicate your thinking aloud before typing. State edge cases explicitly: null or undefined inputs, extreme boundary values, concurrency races, and network timeouts. Writing modular, well-named functions with deterministic unit tests separates junior candidates from staff-level engineers.

4. Antipatterns to Avoid

Avoid reciting memorized definitions without practical context. Never dismiss non-functional requirements such as security (CSRF, injection, token rotation), observability (logging, metrics), and accessibility (ARIA, semantic standards). Always ask clarifying scope questions before writing complex implementations.

Continuous learning: Practice daily, mark completed questions as learned, and revisit difficult concepts.Explore All Interview Tracks →

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools