Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools
DSA

Top 50 DSA Interview Questions

Curated questions covering arrays, linked lists, trees, graphs, sorting, searching, dynamic programming, and Big O notation.

01

What is Big O notation?

Big O notation describes the worst-case time or space complexity of an algorithm in terms of input size n. It represents the growth rate. Common complexities: O(1) constant, O(log n) logarithmic, O(n) linear, O(n log n) linearithmic, O(n^2) quadratic, O(2^n) exponential, O(n!) factorial.

02

What is the difference between time complexity and space complexity?

  • Time complexity - measures how the runtime grows with input size. Expressed in Big O.
  • Space complexity - measures how much extra memory an algorithm uses. Includes auxiliary space (not counting input).
  • Auxiliary space - extra space used by the algorithm excluding input. O(1) auxiliary space means constant extra memory.
03

What is the difference between an array and a linked list?

  • Array - contiguous memory; O(1) random access; O(n) insertion/deletion in middle; fixed size (static arrays).
  • Linked List - non-contiguous nodes with pointers; O(n) access; O(1) insertion/deletion at head; dynamic size.
  • Use arrays for frequent reads; linked lists for frequent insertions/deletions at known positions.
Example
// Array: O(1) access\nint arr[5] = {1,2,3,4,5};\narr[2]; // O(1)\n\n// Linked list: O(n) access\nstruct Node { int data; Node* next; };
04

What is the difference between singly and doubly linked lists?

  • Singly linked list - each node has a next pointer. Can only traverse forward. Less memory.
  • Doubly linked list - each node has next and prev pointers. Can traverse both directions. Easier deletion. More memory.
  • Circular linked list - last node points back to the first.
05

What is a stack and what are its operations?

A stack is a LIFO (Last In First Out) data structure. Operations: push (add to top), pop (remove from top), peek/top (view top), isEmpty. Used for: function call stack, undo operations, expression evaluation, DFS.

Example
class Stack {\n  constructor() { this.items = []; }\n  push(x) { this.items.push(x); }\n  pop()    { return this.items.pop(); }\n  peek()   { return this.items[this.items.length - 1]; }\n  isEmpty(){ return this.items.length === 0; }\n}
06

What is a queue and what are its operations?

A queue is a FIFO (First In First Out) data structure. Operations: enqueue (add to rear), dequeue (remove from front), peek/front, isEmpty. Used for: BFS, task scheduling, print queues, producer-consumer.

Example
class Queue {\n  constructor() { this.items = []; }\n  enqueue(x) { this.items.push(x); }\n  dequeue()  { return this.items.shift(); }\n  front()    { return this.items[0]; }\n  isEmpty()  { return this.items.length === 0; }\n}
07

What is the difference between a stack and a queue?

  • Stack - LIFO. Last element added is the first removed. push/pop from the same end.
  • Queue - FIFO. First element added is the first removed. enqueue at rear, dequeue from front.
  • Deque (double-ended queue) - supports insertion and deletion at both ends.
08

What is a binary search tree (BST)?

A BST is a binary tree where each node's left subtree contains only nodes with smaller values, and the right subtree contains only nodes with larger values. Operations: search, insert, delete - O(log n) average, O(n) worst case (unbalanced).

Example
function search(node, target) {\n  if (!node) return null;\n  if (target === node.val) return node;\n  if (target < node.val) return search(node.left, target);\n  return search(node.right, target);\n}
09

What is the difference between a tree and a graph?

  • Tree - connected, acyclic graph with a root; n nodes, n-1 edges; hierarchical structure; one path between any two nodes.
  • Graph - can have cycles, multiple components, and directed/undirected edges; more general structure.
  • A tree is a special case of a graph.
10

What is the difference between BFS and DFS?

  • BFS (Breadth-First Search) - explores level by level using a queue. Finds shortest path in unweighted graphs. O(V+E).
  • DFS (Depth-First Search) - explores as deep as possible using a stack/recursion. Used for cycle detection, topological sort, connected components. O(V+E).
Example
// BFS\nfunction bfs(graph, start) {\n  const queue = [start], visited = new Set([start]);\n  while (queue.length) {\n    const node = queue.shift();\n    for (const neighbor of graph[node]) {\n      if (!visited.has(neighbor)) { visited.add(neighbor); queue.push(neighbor); }\n    }\n  }\n}
11

What is binary search?

Binary search finds a target in a sorted array by repeatedly halving the search space. Time complexity: O(log n). Requires the array to be sorted.

Example
function binarySearch(arr, target) {\n  let lo = 0, hi = arr.length - 1;\n  while (lo <= hi) {\n    const mid = Math.floor((lo + hi) / 2);\n    if (arr[mid] === target) return mid;\n    else if (arr[mid] < target) lo = mid + 1;\n    else hi = mid - 1;\n  }\n  return -1;\n}
12

What is the difference between merge sort and quick sort?

  • Merge Sort - divide and conquer; always O(n log n); stable; requires O(n) extra space.
  • Quick Sort - divide and conquer; O(n log n) average, O(n^2) worst case; in-place; not stable; faster in practice.
  • Use merge sort for stability; quick sort for in-place sorting.
Example
// Merge Sort\nfunction mergeSort(arr) {\n  if (arr.length <= 1) return arr;\n  const mid = Math.floor(arr.length / 2);\n  const left = mergeSort(arr.slice(0, mid));\n  const right = mergeSort(arr.slice(mid));\n  return merge(left, right);\n}
13

What is dynamic programming?

Dynamic programming solves problems by breaking them into overlapping subproblems and storing results (memoization or tabulation) to avoid redundant computation. Used for: Fibonacci, knapsack, longest common subsequence, shortest path.

Example
// Fibonacci with memoization\nfunction fib(n, memo = {}) {\n  if (n <= 1) return n;\n  if (memo[n]) return memo[n];\n  return memo[n] = fib(n-1, memo) + fib(n-2, memo);\n}\n\n// Tabulation\nfunction fibTab(n) {\n  const dp = [0, 1];\n  for (let i = 2; i <= n; i++) dp[i] = dp[i-1] + dp[i-2];\n  return dp[n];\n}
14

What is the difference between memoization and tabulation?

  • Memoization (top-down) - recursive approach; stores results of subproblems in a cache; only computes needed subproblems.
  • Tabulation (bottom-up) - iterative approach; fills a tl-table from base cases up; computes all subproblems.
  • Tabulation is generally faster (no recursion overhead); memoization is easier to implement.
15

What is a hash table?

A hash tl-table maps keys to values using a hash function. Average O(1) for insert, delete, and lookup. Collisions are handled by chaining (linked lists) or open addressing (probing).

Example
// JavaScript Map (hash table)\nconst map = new Map();\nmap.set("key", "value");\nmap.get("key");    // O(1)\nmap.has("key");    // O(1)\nmap.delete("key"); // O(1)
16

What is the difference between a heap and a BST?

  • Heap - complete binary tree satisfying heap property (parent >= children for max-heap). O(log n) insert/delete. O(1) find-max. Used for priority queues.
  • BST - binary tree with ordering property. O(log n) search/insert/delete. O(n) in-order traversal gives sorted output.
Example
// Min-heap using array\nclass MinHeap {\n  constructor() { this.heap = []; }\n  push(val) { this.heap.push(val); this._bubbleUp(); }\n  pop() { /* swap root with last, remove, sift down */ }\n}
17

What is a trie?

A trie (prefix tree) is a tree where each node represents a character. Used for efficient string search, autocomplete, and spell checking. Search/insert: O(m) where m is string length.

Example
class TrieNode {\n  constructor() { this.children = {}; this.isEnd = false; }\n}\nclass Trie {\n  constructor() { this.root = new TrieNode(); }\n  insert(word) {\n    let node = this.root;\n    for (const ch of word) {\n      if (!node.children[ch]) node.children[ch] = new TrieNode();\n      node = node.children[ch];\n    }\n    node.isEnd = true;\n  }\n}
18

What is topological sorting?

Topological sort orders vertices of a directed acyclic graph (DAG) such that for every edge u->v, u comes before v. Used for task scheduling, build systems, and dependency resolution. Implemented with DFS or Kahn's algorithm (BFS).

Example
// Kahn's algorithm (BFS)\nfunction topoSort(graph, n) {\n  const inDegree = new Array(n).fill(0);\n  for (const [u, v] of graph) inDegree[v]++;\n  const queue = [];\n  for (let i = 0; i < n; i++) if (inDegree[i] === 0) queue.push(i);\n  const result = [];\n  while (queue.length) {\n    const u = queue.shift();\n    result.push(u);\n    for (const v of adj[u]) if (--inDegree[v] === 0) queue.push(v);\n  }\n  return result;\n}
19

What is Dijkstra's algorithm?

Dijkstra's algorithm finds the shortest path from a source to all vertices in a weighted graph with non-negative edges. Uses a min-heap (priority queue). Time complexity: O((V+E) log V).

Example
function dijkstra(graph, start) {\n  const dist = {};\n  const pq = [[0, start]]; // [distance, node]\n  dist[start] = 0;\n  while (pq.length) {\n    const [d, u] = pq.shift(); // use min-heap in practice\n    if (d > (dist[u] ?? Infinity)) continue;\n    for (const [v, w] of graph[u]) {\n      if ((dist[u] + w) < (dist[v] ?? Infinity)) {\n        dist[v] = dist[u] + w;\n        pq.push([dist[v], v]);\n      }\n    }\n  }\n  return dist;\n}
20

What is the two-pointer technique?

Two pointers use two indices to traverse an array or linked list, often from both ends or at different speeds. Used for: finding pairs with a sum, removing duplicates, detecting cycles (Floyd's algorithm).

Example
// Find pair with target sum in sorted array\nfunction twoSum(arr, target) {\n  let lo = 0, hi = arr.length - 1;\n  while (lo < hi) {\n    const sum = arr[lo] + arr[hi];\n    if (sum === target) return [lo, hi];\n    else if (sum < target) lo++;\n    else hi--;\n  }\n  return null;\n}
21

What is the sliding window technique?

The sliding window technique maintains a window of elements and slides it across the array to solve subarray/substring problems efficiently. Reduces O(n^2) brute force to O(n).

Example
// Maximum sum subarray of size k\nfunction maxSumSubarray(arr, k) {\n  let sum = arr.slice(0, k).reduce((a, b) => a + b, 0);\n  let max = sum;\n  for (let i = k; i < arr.length; i++) {\n    sum += arr[i] - arr[i - k];\n    max = Math.max(max, sum);\n  }\n  return max;\n}
22

What is Floyd's cycle detection algorithm?

Floyd's algorithm (tortoise and hare) detects cycles in a linked list using two pointers - slow (moves 1 step) and fast (moves 2 steps). If they meet, a cycle exists. Time: O(n), Space: O(1).

Example
function hasCycle(head) {\n  let slow = head, fast = head;\n  while (fast && fast.next) {\n    slow = slow.next;\n    fast = fast.next.next;\n    if (slow === fast) return true;\n  }\n  return false;\n}
23

What is the difference between linear and binary search?

  • Linear search - checks each element sequentially; O(n); works on unsorted arrays.
  • Binary search - halves the search space each step; O(log n); requires sorted array.
  • For small arrays or unsorted data, linear search is fine. For large sorted data, always use binary search.
24

What are the common sorting algorithms and their complexities?

  • Bubble Sort - O(n^2) average; simple but inefficient.
  • Selection Sort - O(n^2); in-place.
  • Insertion Sort - O(n^2) average, O(n) best; good for small/nearly sorted arrays.
  • Merge Sort - O(n log n); stable; O(n) space.
  • Quick Sort - O(n log n) average; in-place.
  • Heap Sort - O(n log n); in-place; not stable.
  • Counting/Radix Sort - O(n+k); for integers.
25

What is a graph and what are its representations?

  • Adjacency Matrix - 2D array; O(1) edge lookup; O(V^2) space; good for dense graphs.
  • Adjacency List - array of lists; O(V+E) space; good for sparse graphs.
  • Edge List - list of edges; simple; used in some algorithms like Kruskal's.
Example
// Adjacency list\nconst graph = {\n  A: ["B", "C"],\n  B: ["A", "D"],\n  C: ["A"],\n  D: ["B"]\n};\n\n// Adjacency matrix\nconst matrix = [\n  [0, 1, 1, 0],\n  [1, 0, 0, 1],\n  [1, 0, 0, 0],\n  [0, 1, 0, 0]\n];
26

What is the knapsack problem?

The 0/1 knapsack problem: given items with weights and values, find the maximum value that fits in a knapsack of capacity W. Each item can be taken (1) or not (0). Solved with DP in O(nW) time.

Example
function knapsack(weights, values, W) {\n  const n = weights.length;\n  const dp = Array(n+1).fill(null).map(() => Array(W+1).fill(0));\n  for (let i = 1; i <= n; i++)\n    for (let w = 0; w <= W; w++) {\n      dp[i][w] = dp[i-1][w];\n      if (weights[i-1] <= w)\n        dp[i][w] = Math.max(dp[i][w], dp[i-1][w-weights[i-1]] + values[i-1]);\n    }\n  return dp[n][W];\n}
27

What is the difference between Prim's and Kruskal's algorithm?

  • Prim's - grows a minimum spanning tree from a starting vertex. Uses a priority queue. O(E log V). Better for dense graphs.
  • Kruskal's - sorts all edges by weight and adds them if they do not create a cycle (Union-Find). O(E log E). Better for sparse graphs.
  • Both find the Minimum Spanning Tree (MST) of a weighted undirected graph.
28

What is the difference between Bellman-Ford and Dijkstra?

  • Dijkstra - O((V+E) log V). Does not work with negative edge weights.
  • Bellman-Ford - O(VE). Works with negative edge weights. Can detect negative cycles.
  • Use Dijkstra for non-negative weights; Bellman-Ford when negative weights are possible.
29

What is the difference between a balanced and unbalanced BST?

  • Balanced BST - height is O(log n). Operations are O(log n). Examples: AVL tree, Red-Black tree.
  • Unbalanced BST - can degrade to O(n) height (like a linked list) if elements are inserted in sorted order.
  • Java TreeMap and C++ std::map use Red-Black trees. Python sortedcontainers uses a B-tree variant.
30

What is the difference between AVL tree and Red-Black tree?

  • AVL tree - strictly balanced (height difference <= 1 for every node). Faster lookups. More rotations on insert/delete.
  • Red-Black tree - loosely balanced. Fewer rotations on insert/delete. Faster insertions. Used in most standard library implementations.
31

What is the difference between a min-heap and max-heap?

  • Min-heap - parent is always <= children. Root is the minimum element. Used for: Dijkstra, Prim's, priority queues where smallest is highest priority.
  • Max-heap - parent is always >= children. Root is the maximum element. Used for: heap sort, priority queues where largest is highest priority.
Example
// Priority queue (min-heap) in JavaScript\nconst pq = new MinPriorityQueue();\npq.enqueue("task1", 3); // priority 3\npq.enqueue("task2", 1); // priority 1\npq.dequeue(); // returns task2 (lowest priority number)
32

What is the difference between DFS pre-order, in-order, and post-order traversal?

  • Pre-order (Root, Left, Right) - visits root first. Used for copying a tree or prefix expression.
  • In-order (Left, Root, Right) - visits nodes in sorted order for BST. Used to get sorted output.
  • Post-order (Left, Right, Root) - visits root last. Used for deleting a tree or postfix expression.
Example
function inOrder(node) {\n  if (!node) return;\n  inOrder(node.left);\n  console.log(node.val); // sorted for BST\n  inOrder(node.right);\n}
33

What is the difference between a complete binary tree and a full binary tree?

  • Full binary tree - every node has either 0 or 2 children. No node has exactly 1 child.
  • Complete binary tree - all levels are fully filled except possibly the last, which is filled from left to right.
  • Perfect binary tree - all internal nodes have 2 children and all leaves are at the same level.
34

What is the difference between depth and height of a tree?

  • Depth of a node - number of edges from the root to that node. Root has depth 0.
  • Height of a node - number of edges on the longest path from that node to a leaf.
  • Height of a tree - height of the root node.
35

What is the difference between a directed and undirected graph?

  • Undirected graph - edges have no direction. If A connects to B, B connects to A.
  • Directed graph (digraph) - edges have direction. A->B does not imply B->A.
  • Weighted graph - edges have weights/costs. Used in shortest path algorithms.
36

What is the difference between strongly connected and weakly connected graphs?

  • Strongly connected - in a directed graph, every vertex is reachable from every other vertex.
  • Weakly connected - the underlying undirected graph is connected, but not all directed paths exist.
  • Connected (undirected) - there is a path between every pair of vertices.
37

What is the difference between a greedy algorithm and dynamic programming?

  • Greedy - makes the locally optimal choice at each step. Fast but does not always give the global optimum. Works for: activity selection, Huffman coding, Dijkstra.
  • Dynamic programming - considers all subproblems and stores results. Always finds the global optimum for problems with optimal substructure and overlapping subproblems.
38

What is the difference between divide and conquer and dynamic programming?

  • Divide and conquer - divides problem into independent subproblems, solves recursively, combines results. Subproblems do NOT overlap. Examples: merge sort, binary search.
  • Dynamic programming - subproblems DO overlap. Stores results to avoid recomputation. Examples: Fibonacci, knapsack, LCS.
39

What is the difference between a stack-based and queue-based approach for graph traversal?

  • Stack (DFS) - explores as deep as possible before backtracking. Finds any path. Used for cycle detection, topological sort.
  • Queue (BFS) - explores all neighbors at current depth before going deeper. Finds shortest path in unweighted graphs.
40

What is the difference between Huffman coding and run-length encoding?

  • Huffman coding - variable-length prefix codes. Frequent characters get shorter codes. Optimal for symbol-by-symbol encoding.
  • Run-length encoding (RLE) - replaces consecutive repeated characters with count + character. Efficient for data with many consecutive repeats (images, simple text).
41

What is the difference between a segment tree and a Fenwick tree (BIT)?

  • Segment tree - supports range queries (sum, min, max) and point/range updates. O(log n) for both. More flexible.
  • Fenwick tree (Binary Indexed Tree) - simpler implementation. Supports prefix sum queries and point updates. O(log n). Less memory.
Example
// Fenwick tree prefix sum\nclass BIT {\n  constructor(n) { this.tree = new Array(n+1).fill(0); }\n  update(i, delta) { for (; i < this.tree.length; i += i & -i) this.tree[i] += delta; }\n  query(i) { let s = 0; for (; i > 0; i -= i & -i) s += this.tree[i]; return s; }\n}
42

What is the difference between a stable and unstable sorting algorithm?

  • Stable sort - preserves the relative order of equal elements. Examples: merge sort, insertion sort, Timsort.
  • Unstable sort - may change the relative order of equal elements. Examples: quick sort, heap sort, selection sort.
  • Stability matters when sorting objects by multiple keys.
43

What is the difference between amortized and average-case complexity?

  • Average-case complexity - expected performance over all possible inputs of size n (requires probability distribution).
  • Amortized complexity - average performance per operation over a sequence of operations. No probability involved.
  • Example: dynamic array push_back is O(1) amortized (occasional O(n) resize is spread across all operations).
44

What is the difference between a sparse and dense graph?

  • Dense graph - has many edges, close to the maximum E = V*(V-1)/2. Adjacency matrix is more efficient.
  • Sparse graph - has few edges, much less than V^2. Adjacency list is more efficient.
  • Most real-world graphs (social networks, web graphs) are sparse.
45

What is the difference between a recursive and iterative DFS?

  • Recursive DFS - uses the call stack implicitly. Simpler code. Risk of stack overflow for deep graphs.
  • Iterative DFS - uses an explicit stack. No stack overflow risk. Slightly more complex code.
Example
// Iterative DFS\nfunction dfs(graph, start) {\n  const stack = [start], visited = new Set();\n  while (stack.length) {\n    const node = stack.pop();\n    if (visited.has(node)) continue;\n    visited.add(node);\n    for (const neighbor of graph[node]) stack.push(neighbor);\n  }\n}
46

What is the difference between a priority queue and a regular queue?

  • Regular queue - FIFO. Elements dequeued in insertion order.
  • Priority queue - elements dequeued based on priority (highest or lowest first). Implemented with a heap. O(log n) enqueue/dequeue.
  • Used in Dijkstra, Prim's, A*, and task scheduling.
47

What is the difference between Union-Find and BFS/DFS for connected components?

  • Union-Find (Disjoint Set Union) - efficiently merges sets and checks if two elements are in the same set. O(alpha(n)) per operation (nearly O(1)). Best for dynamic connectivity.
  • BFS/DFS - traverses the graph to find all connected components. O(V+E). Best for static graphs.
Example
class UnionFind {\n  constructor(n) { this.parent = Array.from({length:n},(_,i)=>i); }\n  find(x) { return this.parent[x]===x ? x : this.parent[x]=this.find(this.parent[x]); }\n  union(x,y) { this.parent[this.find(x)] = this.find(y); }\n  connected(x,y) { return this.find(x)===this.find(y); }\n}
48

What is the difference between LCS and LIS?

  • LCS (Longest Common Subsequence) - longest subsequence common to two sequences. DP solution: O(m*n) time and space.
  • LIS (Longest Increasing Subsequence) - longest subsequence of a single array where elements are strictly increasing. DP: O(n^2). Optimized with binary search: O(n log n).
Example
// LIS - O(n^2) DP\nfunction lis(arr) {\n  const dp = new Array(arr.length).fill(1);\n  for (let i = 1; i < arr.length; i++)\n    for (let j = 0; j < i; j++)\n      if (arr[j] < arr[i]) dp[i] = Math.max(dp[i], dp[j]+1);\n  return Math.max(...dp);\n}
49

What is the difference between a complete graph and a bipartite graph?

  • Complete graph (K_n) - every vertex is connected to every other vertex. Has n*(n-1)/2 edges.
  • Bipartite graph - vertices can be divided into two sets such that every edge connects a vertex from one set to the other. No edges within the same set. Can be checked with BFS/DFS (2-coloring).
50

What is the difference between space-optimized DP and standard DP?

  • Standard DP - uses a full 2D table. O(n*m) space.
  • Space-optimized DP - uses only the previous row/column. O(n) or O(1) space. Possible when current state only depends on adjacent states.
Example
// Standard LCS: O(m*n) space\nconst dp = Array(m+1).fill(null).map(()=>Array(n+1).fill(0));\n\n// Space-optimized: O(n) space\nlet prev = new Array(n+1).fill(0);\nlet curr = new Array(n+1).fill(0);\n// Use only two rows

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.