Skip to main content
DevHivesBlog

Search the blog

Find a post by title, tag or topic

50 DSA Interview Questions for 2026 Fresher Coding Rounds

The 50 DSA questions most likely to appear in 2026 IT-services and product-company coding rounds, with solutions and complexity. Start with arrays, strings, stacks and linked lists — services loops lean on them.

Arnab Biswas9 min read
WhatsApp
A staircase with five steps and a flag at the top, representing the 50 DSA questions as a climbing path to coding round success.

Say you have an Infosys or TCS interview next week and fifty DSA questions on your list. The first question is often "reverse an array" or "find two numbers that add up to a target". A weak answer is a long silence followed by a nested loop. A strong one names the simple loop, says what it costs, then improves it out loud.

Drill arrays, strings, basic stacks and queues, and easy linked lists first, because off-campus IT-services loops lean on them. Add trees and graphs, and dynamic programming as well, only if you are aiming at product companies. Below are fifty questions grouped by topic, each with a short solution, its time and space complexity, and what the interviewer is checking.

Which DSA topics each type of company asks

IT-services loops stay mostly on arrays and strings, with some stacks and queues and easy linked lists, while product-company loops add trees and graphs, plus dynamic programming and medium or hard problems.

Skipping DSA is not an option for a services role either. Internshala reports that more than 70% of technical interviews feature data structures and algorithms questions. The Infosys drive is services work, so the middle column of this table is where most of those seats get decided.

The topic list comes from the GeeksforGeeks Top 100 DSA questions, which groups questions by data structure. The split between the two columns is my reading of how the two kinds of loop differ, not an official syllabus.

TopicIT-services loopsProduct-company loopsDifficulty to expect
ArraysAlmost alwaysAlmost alwaysEasy to medium
StringsAlmost alwaysOftenEasy to medium
Stacks and queuesOftenOftenEasy
Linked listsSometimes, easy onesOftenEasy to medium
Searching and sortingOften, as follow-upsOftenEasy
TreesRareCommonMedium
GraphsRareCommonMedium to hard
Dynamic programmingRareCommonMedium to hard
Heaps and bit manipulationRareSometimesMedium

Targeting TCS? Read our note on TCS's Q2 FY27 fresher hiring before deciding how far down the table to go.

Optional extra: this Apna College video walks through must-do placement problems, so watch it after you have tried the first ten questions below.

Watch: Must Do "DSA Problems" for Tech Placements & Internships — Apna College (YouTube)

Array questions (1-10)

Arrays are the most common first question, and the interviewer checks whether you can reach a loop-based answer and say why it is O(n).

# 1. Reverse an array: O(n) time, O(1) space
def rev(a, i, j):
    while i < j:
        a[i], a[j] = a[j], a[i]
        i, j = i + 1, j - 1
    return a
# call: rev(a, 0, len(a) - 1)
# 2. Largest and second largest: O(n) time, O(1) space (second must be strictly smaller than first, so [5, 5] returns -inf for second)
def top_two(a):
    first = second = float('-inf')
    for x in a:
        if x > first:
            first, second = x, first
        elif first > x > second:
            second = x
    return first, second
# 3. Two-sum: O(n) time, O(n) space
def two_sum(a, target):
    seen = {}
    for i, x in enumerate(a):
        if target - x in seen:
            return seen[target - x], i
        seen[x] = i
# 4. Move zeros to the end: O(n) time, O(1) space
def move_zeros(a):
    k = 0
    for x in a:
        if x != 0:
            a[k] = x; k += 1
    for i in range(k, len(a)):
        a[i] = 0
    return a
# 5. Kadane's maximum subarray: O(n) time, O(1) space
def max_subarray(a):
    best = cur = a[0]
    for x in a[1:]:
        cur = max(x, cur + x)
        best = max(best, cur)
    return best
# 6. Rotate right by k: O(n) time, O(1) space (k = 0 works because rev(a, 0, -1) does nothing)
def rotate(a, k):
    n = len(a); k %= n
    rev(a, 0, n - 1); rev(a, 0, k - 1); rev(a, k, n - 1)
# 7. Missing number in 0..n: O(n) time, O(1) space
def missing(a):
    n = len(a)
    return n * (n + 1) // 2 - sum(a)
# 8. Remove duplicates from a sorted array: O(n) time, O(1) space
def dedupe_sorted(a):
    if not a: return 0
    k = 1
    for i in range(1, len(a)):
        if a[i] != a[k - 1]:
            a[k] = a[i]; k += 1
    return k
# 9. Merge two sorted arrays: O(n + m) time, O(n + m) space
def merge(a, b):
    i = j = 0; out = []
    while i < len(a) and j < len(b):
        if a[i] <= b[j]: out.append(a[i]); i += 1
        else: out.append(b[j]); j += 1
    return out + a[i:] + b[j:]
# 10. Majority element (Boyer-Moore vote): O(n) time, O(1) space
def majority(a):
    cand, count = None, 0
    for x in a:
        if count == 0: cand = x
        count += 1 if x == cand else -1
    return cand

Drill these ten before anything else. Question 10 assumes a majority exists, so say that assumption out loud before you code it.

Here is a weak and a strong spoken answer to question 3. Weak: silence, then 'I will loop inside a loop.' Strong: 'The simple way checks every pair, which is O(n²) time and O(1) space. I can do better by storing each number I have seen in a dictionary, then asking whether target minus the current number is already there. That is O(n) time and O(n) space, and I am trading memory for speed.'

Question 10 in plain words: keep one candidate and a count. A value equal to the candidate adds one, a different value cancels one, and when the count hits zero you pick a new candidate. A true majority outnumbers everything else, so it survives the cancelling. On [2, 2, 1, 1, 2] the count goes 1, 2, 1, 0, 1 and the answer is 2.

String questions (11-20)

String questions test whether you handle edge cases such as empty input and letter case, then spaces, before you reach for a clever trick.

from collections import Counter
# 11. Reverse a string: O(n) time, O(n) space
def reverse_str(s): return s[::-1]
# 12. Palindrome, ignoring case and spaces: O(n) time, O(n) space
def is_palindrome(s):
    clean = [c.lower() for c in s if c.isalnum()]
    return clean == clean[::-1]
# 13. Valid anagram: O(n) time, O(k) space for k distinct characters
def is_anagram(s, t): return Counter(s) == Counter(t)
# 14. First non-repeating character: O(n) time, O(k) space
def first_unique(s):
    counts = Counter(s)
    for c in s:
        if counts[c] == 1: return c
    return None
# 15. Count vowels: O(n) time, O(1) space
def vowels(s): return sum(c in 'aeiouAEIOU' for c in s)
# 16. Longest common prefix: O(n * m) time, O(m) space, n = number of words, m = length of the first word
def lcp(words):
    if not words: return ""
    p = words[0]
    for w in words[1:]:
        while not w.startswith(p): p = p[:-1]
    return p
# 17. Is b a rotation of a? O(n) time with a good substring search (n = len(a)), O(n) space
def is_rotation(a, b): return len(a) == len(b) and b in a + a
# 18. Remove duplicate characters, keep order: O(n) time, O(n) space
def remove_dupes(s): return "".join(dict.fromkeys(s))
# 19. String compression, "aabccc" to "a2b1c3": O(n) time, O(n) space
def compress(s):
    out, i = [], 0
    while i < len(s):
        j = i
        while j < len(s) and s[j] == s[i]: j += 1
        out.append(s[i] + str(j - i)); i = j
    r = "".join(out)
    return r if len(r) < len(s) else s
# 20. Longest substring without repeating characters: O(n) time, O(k) space
def longest_unique(s):
    last, start, best = {}, 0, 0
    for i, c in enumerate(s):
        if last.get(c, -1) >= start: start = last[c] + 1
        last[c] = i
        best = max(best, i - start + 1)
    return best

Question 20 in plain words: keep a window that never contains a repeated character. When the current character was last seen inside the window, move the window start just past that earlier spot. On "abcabcbb" the window grows to "abc" (best 3), then start moves to 1, 2, 3 as a, b and c repeat. It later shrinks to "cb" and "b", so the function returns 3.

Question 13 has two honest answers. Here is how sorting both strings compares with the hash-map count above:

Pros

  • Sorting is one line: sorted(s) == sorted(t).
  • It is easy to explain under pressure.

Cons

  • Sorting costs O(n log n), against O(n) for counting.
  • The interviewer will almost always ask for the faster version next.

Linked list questions (21-28)

Linked list questions check whether you can track pointers without losing the rest of the list.

class Node:
    def __init__(self, val, nxt=None):
        self.val, self.next = val, nxt
# 21. Reverse a list: O(n) time, O(1) space
def reverse_list(head):
    prev = None
    while head:
        head.next, prev, head = prev, head, head.next
    return prev
# 22. Middle node (slow and fast pointers): O(n) time, O(1) space
def middle(head):
    slow = fast = head
    while fast and fast.next:
        slow, fast = slow.next, fast.next.next
    return slow
# 23. Detect a cycle: O(n) time, O(1) space
def has_cycle(head):
    slow = fast = head
    while fast and fast.next:
        slow, fast = slow.next, fast.next.next
        if slow is fast: return True
    return False
# 24. Merge two sorted lists: O(n + m) time, O(1) space
def merge_lists(a, b):
    dummy = tail = Node(0)
    while a and b:
        if a.val <= b.val: tail.next, a = a, a.next
        else: tail.next, b = b, b.next
        tail = tail.next
    tail.next = a or b
    return dummy.next
# 25. Remove the nth node from the end: O(n) time, O(1) space
def remove_nth(head, n):
    dummy = Node(0, head); fast = slow = dummy
    for _ in range(n): fast = fast.next
    while fast.next:
        fast, slow = fast.next, slow.next
    slow.next = slow.next.next
    return dummy.next
# 26. Palindrome list (changes the second half): O(n) time, O(1) space
def is_pal(head):
    second = reverse_list(middle(head))
    while second:
        if head.val != second.val: return False
        head, second = head.next, second.next
    return True
# 27. Delete a node given only that node (not the tail): O(1) time and space
def delete_node(node):
    node.val, node.next = node.next.val, node.next.next
# 28. Intersection of two lists: O(n + m) time, O(1) space
def intersection(a, b):
    p, q = a, b
    while p is not q:
        p = p.next if p else b
        q = q.next if q else a
    return p

Question 21 in plain words: the right side of head.next, prev, head = prev, head, head.next is worked out first, using the old values. Then the assignments run left to right, so the current node points backwards, prev moves up to the current node, and head moves on to the node that came next.

Question 25 in plain words: move fast n steps ahead, then move both pointers until fast sits on the last node. Slow is now just before the node to delete, so slow.next = slow.next.next skips it.

Question 28 in plain words: each pointer walks its own list and then switches to the start of the other list. Both walk the same total distance, so they meet at the shared node, or both reach the end together if there is none. Take a = 1, 2, 8, 9 and b = 5, 8, 9, where 8 and 9 are shared. The pairs (p, q) go (1, 5), (2, 8), (8, 9), (9, None), (None, 1), (5, 2), (8, 8). They meet, so the function returns the node 8.

Stack and queue questions (29-36)

Stack and queue questions check whether you know when last-in-first-out or first-in-first-out fits the problem.

import operator
from collections import deque
# 29. Valid parentheses: O(n) time, O(n) space
def valid(s):
    pairs = {')': '(', ']': '[', '}': '{'}
    stack = []
    for c in s:
        if c in pairs:
            if not stack or stack.pop() != pairs[c]: return False
        else: stack.append(c)
    return not stack
# 30. Stack using an array: O(1) per operation (amortised push)
class Stack:
    def __init__(self): self.items = []
    def push(self, x): self.items.append(x)
    def pop(self): return self.items.pop()
    def peek(self): return self.items[-1]
# 31. Queue using two stacks: amortised O(1) per operation, O(n) space
class Queue:
    def __init__(self): self.inbox, self.outbox = [], []
    def push(self, x): self.inbox.append(x)
    def pop(self):
        if not self.outbox:
            while self.inbox: self.outbox.append(self.inbox.pop())
        return self.outbox.pop()
# 32. Min stack: O(1) per operation, O(n) space
class MinStack:
    def __init__(self): self.s = []
    def push(self, x):
        m = min(x, self.s[-1][1]) if self.s else x
        self.s.append((x, m))
    def pop(self): return self.s.pop()[0]
    def get_min(self): return self.s[-1][1]
# 33. Next greater element: O(n) time, O(n) space
def next_greater(a):
    res, stack = [-1] * len(a), []
    for i, x in enumerate(a):
        while stack and a[stack[-1]] < x:
            res[stack.pop()] = x
        stack.append(i)
    return res
# 34. Evaluate a postfix expression: O(n) time, O(n) space
OPS = {'+': operator.add, '-': operator.sub,
       '*': operator.mul, '/': lambda a, b: int(a / b)}
def eval_postfix(tokens):
    st = []
    for t in tokens:
        if t in OPS:
            b, a = st.pop(), st.pop()
            st.append(OPS[t](a, b))
        else: st.append(int(t))
    return st[0]
# 35. Circular queue of size k: O(1) per operation, O(k) space
class CircularQueue:
    def __init__(self, k):
        self.q, self.head, self.size = [None] * k, 0, 0
    def enqueue(self, x):
        if self.size == len(self.q): return False
        self.q[(self.head + self.size) % len(self.q)] = x
        self.size += 1; return True
    def dequeue(self):
        if self.size == 0: return None
        x = self.q[self.head]
        self.head = (self.head + 1) % len(self.q); self.size -= 1
        return x
# 36. Reverse a queue with a stack: O(n) time, O(n) space
def reverse_queue(q):
    stack = []
    while q: stack.append(q.popleft())
    while stack: q.append(stack.pop())
    return q

Here is how the stack in question 29 changes on the input ({[]}):

  1. Read (: push it. Stack: (
  2. Read {: push it. Stack: ( {
  3. Read [: push it. Stack: ( { [
  4. Read ]: pop [, which matches. Stack: ( {
  5. Read }: pop {, which matches. Stack: (
  6. Read ): pop (, which matches. The stack is empty, so the string is valid.

Question 33 in plain words: the stack holds indexes of numbers still waiting for a bigger one. Each new number settles every waiting number smaller than it. On [2, 1, 3], the 1 and then the 2 are both settled by the 3, so the result is [3, 3, -1].

Searching, sorting and recursion basics (37-42)

Binary search and the basic sorts are favourite follow-ups because they show whether you understand time complexity, not just syntax.

from functools import lru_cache
# 37. Binary search on a sorted array: O(log n) time, O(1) space
def binary_search(a, x):
    lo, hi = 0, len(a) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if a[mid] == x: return mid
        if a[mid] < x: lo = mid + 1
        else: hi = mid - 1
    return -1
# 38. First and last position: O(log n) time, O(1) space
def bound(a, x, first):
    lo, hi, ans = 0, len(a) - 1, -1
    while lo <= hi:
        mid = (lo + hi) // 2
        if a[mid] == x:
            ans = mid
            if first: hi = mid - 1
            else: lo = mid + 1
        elif a[mid] < x: lo = mid + 1
        else: hi = mid - 1
    return ans
# answer: [bound(a, x, True), bound(a, x, False)]
# 39. Merge sort (uses merge from question 9): O(n log n) time, O(n) space
def merge_sort(a):
    if len(a) <= 1: return a
    m = len(a) // 2
    return merge(merge_sort(a[:m]), merge_sort(a[m:]))
# 40. Quick sort (simple, not in place): O(n log n) average time
def quick_sort(a):
    if len(a) <= 1: return a
    p = a[len(a) // 2]
    return (quick_sort([x for x in a if x < p]) + [x for x in a if x == p]
            + quick_sort([x for x in a if x > p]))
# 41. Factorial: O(n) time, O(n) stack. Fibonacci with memo: O(n) time
# plain version, O(2^n): def fib_plain(n): return n if n < 2 else fib_plain(n - 1) + fib_plain(n - 2)
def fact(n): return 1 if n <= 1 else n * fact(n - 1)
@lru_cache(None)
def fib(n): return n if n < 2 else fib(n - 1) + fib(n - 2)
# 42. Power x^n for n >= 0: O(log n) time, O(log n) stack
def power(x, n):
    if n == 0: return 1
    half = power(x, n // 2)
    return half * half * (x if n % 2 else 1)
SortBestAverageWorstExtra space
Bubble sort (with an early-exit flag)O(n)O(n²)O(n²)O(1)
Merge sortO(n log n)O(n log n)O(n log n)O(n)
Quick sort (in place)O(n log n)O(n log n)O(n²)O(log n)

Trees, graphs and dynamic programming (43-50)

These topics mostly appear in product-company loops, so a fresher aiming at services firms can leave them for later.

from collections import deque
# 43. Inorder traversal: O(n) time, O(h) stack for tree height h
def inorder(node):
    return inorder(node.left) + [node.val] + inorder(node.right) if node else []
# 44. Maximum depth: O(n) time, O(h) space
def depth(node):
    return 1 + max(depth(node.left), depth(node.right)) if node else 0
# 45. Validate a BST: O(n) time, O(h) space
def is_bst(node, lo=float('-inf'), hi=float('inf')):
    if not node: return True
    if not lo < node.val < hi: return False
    return is_bst(node.left, lo, node.val) and is_bst(node.right, node.val, hi)
# 46. Level-order traversal: O(n) time, O(n) space
def level_order(root):
    if not root: return []
    out, q = [], deque([root])
    while q:
        level = []
        for _ in range(len(q)):
            n = q.popleft(); level.append(n.val)
            if n.left: q.append(n.left)
            if n.right: q.append(n.right)
        out.append(level)
    return out
# 47. BFS on a graph (adjacency dict): O(V + E) time, O(V) space
def bfs(graph, start):
    seen, q, order = {start}, deque([start]), []
    while q:
        u = q.popleft(); order.append(u)
        for v in graph[u]:
            if v not in seen: seen.add(v); q.append(v)
    return order
# 48. Count islands with DFS: O(rows * cols) time and space
def count_islands(grid):
    rows, cols, count = len(grid), len(grid[0]), 0
    def sink(r, c):
        if 0 <= r < rows and 0 <= c < cols and grid[r][c] == '1':
            grid[r][c] = '0'
            sink(r + 1, c); sink(r - 1, c); sink(r, c + 1); sink(r, c - 1)
    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == '1': count += 1; sink(r, c)
    return count
# 49. Climbing stairs (1 or 2 steps): O(n) time, O(1) space
def climb(n):
    a, b = 1, 1
    for _ in range(n): a, b = b, a + b
    return a
# 50. Coin change, fewest coins: O(amount * coins) time, O(amount) space
def coin_change(coins, amount):
    dp = [0] + [float('inf')] * amount
    for x in range(1, amount + 1):
        for c in coins:
            if c <= x: dp[x] = min(dp[x], dp[x - c] + 1)
    return dp[amount] if dp[amount] != float('inf') else -1

Drill order for the next two weeks

Spend week one on questions 1-36 and week two on questions 37-42, then on 43-50 only if you are aiming at product companies, because clear explanation at the fresher level counts for more than complex code.

Drill from the bottom up: arrays and strings first, trees and graphs last
Drill from the bottom up: arrays and strings first, trees and graphs last

Run every question through the same four steps:

  1. Solve

    Write the simple version first, even if it is slow.

  2. Explain aloud

    Talk through it as if the interviewer were across the table. Say why each line exists.

  3. State complexity

    Give time and space, then name the line that sets each one.

  4. Redo without notes

    Close the file. Come back the next day and write it again from a blank page.

This page is the question bank. For the patterns behind these questions and how company rounds are structured, read Crack Your First Coding Interview in India. To show this practice on paper, see which skills to list on a fresher resume.

Someone still has to read generated code and say whether it runs in O(n) or O(n²), so practise saying it.

Pick five array questions from the bank today. Solve each without looking at the answer, then say your solution out loud and state its time and space complexity. Tomorrow, do the same with five string questions.

ShareWhatsAppLinkedInX

Picked from the tags and topic of this post.

A large question mark, representing the ML interview questions for freshers.
career growth11 min read

Machine Learning Interview Questions for Freshers (2026)

ML theory questions are now part of normal fresher hiring at Indian IT service companies. Prepare ten core questions with a three-part answer pattern, not ninety shallow ones.

Arnab Biswas
Four interview rounds with the next one open, showing Mphasis's multi-stage process.
career growth10 min read

Mphasis Interview Questions for .NET Developer: Fresher Guide 2026

Clear Mphasis's AMCAT test, group discussion, technical round and HR round with the exact topics asked. Practice the C#, OOP, SQL, LINQ, and EF Core questions from this post. Read the 24-month bond terms before you sign and follow a 30-day prep plan to pass.

Arnab Biswas