0% found this document useful (0 votes)
2 views14 pages

Python DSA Interview Solutions

Uploaded by

Joni Hansome
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views14 pages

Python DSA Interview Solutions

Uploaded by

Joni Hansome
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 14

Python + DSA: 50 Practice Problems

with Answers
Each problem includes a concise Python solution and time/space complexity. Use these as
templates in interviews.

1) Reverse a string
def reverse_string(s: str) -> str:
return s[::-1]
# Complexity: O(n) time, O(n) space (for new string)

2) Check palindrome
def is_palindrome(s: str) -> bool:
s = ''.join(ch.lower() for ch in s if ch.isalnum())
return s == s[::-1]
# Complexity: O(n) time, O(n) space

3) Factorial (loop & recursion)


def fact_iter(n: int) -> int:
res = 1
for i in range(2, n+1):
res *= i
return res

def fact_rec(n: int) -> int:


return 1 if n <= 1 else n * fact_rec(n-1)
# Complexity: O(n) time; O(1) space iter, O(n) stack rec

4) Fibonacci sequence
def fib(n: int) -> int:
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n+1):
a, b = b, a+b
return b
# Complexity: O(n) time, O(1) space
5) Prime number check
def is_prime(n: int) -> bool:
if n < 2:
return False
if n % 2 == 0:
return n == 2
i = 3
while i * i <= n:
if n % i == 0:
return False
i += 2
return True
# Complexity: O(sqrt(n)) time, O(1) space

6) Find GCD & LCM


def gcd(a: int, b: int) -> int:
while b:
a, b = b, a % b
return a

def lcm(a: int, b: int) -> int:


return abs(a*b) // gcd(a, b) if a and b else 0
# Complexity: O(log min(a,b)) time, O(1) space

7) Armstrong number
def is_armstrong(n: int) -> bool:
s = str(n)
p = len(s)
return n == sum(int(ch)**p for ch in s)
# Complexity: O(d) time, O(1) space

8) Count vowels in string


def count_vowels(s: str) -> int:
vowels = set('aeiouAEIOU')
return sum(1 for ch in s if ch in vowels)
# Complexity: O(n) time, O(1) space
9) Anagram check
from collections import Counter
def are_anagrams(a: str, b: str) -> bool:
a = ''.join(sorted(ch.lower() for ch in a if ch.isalnum()))
b = ''.join(sorted(ch.lower() for ch in b if ch.isalnum()))
return a == b
# Complexity: O(n log n) time, O(n) space

10) Longest word in string


def longest_word(s: str) -> str:
words = s.split()
return max(words, key=len) if words else ''
# Complexity: O(n) time, O(k) space (k words)

11) Remove duplicates from list


def remove_dups(lst):
seen = set()
out = []
for x in lst:
if x not in seen:
seen.add(x)
out.append(x)
return out
# Complexity: O(n) time, O(n) space

12) Find max & min in list


def min_max(lst):
if not lst:
return None, None
mn = mx = lst[0]
for x in lst[1:]:
if x < mn: mn = x
if x > mx: mx = x
return mn, mx
# Complexity: O(n) time, O(1) space

13) Second largest element


def second_largest(nums):
first = second = None
for x in nums:
if first is None or x > first:
second, first = first, x
elif x != first and (second is None or x > second):
second = x
return second
# Complexity: O(n) time, O(1) space

14) Merge two sorted arrays


def merge_sorted(a, b):
i = j = 0
res = []
while i < len(a) and j < len(b):
if a[i] <= b[j]:
res.append(a[i]); i += 1
else:
res.append(b[j]); j += 1
res.extend(a[i:]); res.extend(b[j:])
return res
# Complexity: O(n+m) time, O(n+m) space

15) Rotate array by k steps


def rotate(nums, k):
n = len(nums)
k %= n
def rev(i, j):
while i < j:
nums[i], nums[j] = nums[j], nums[i]
i += 1; j -= 1
rev(0, n-1); rev(0, k-1); rev(k, n-1)
return nums
# Complexity: O(n) time, O(1) space

16) Missing number in array (0..n)


def missing_number(nums):
n = len(nums)
return n*(n+1)//2 - sum(nums)
# Complexity: O(n) time, O(1) space
17) Find duplicates in array
def find_duplicates(nums):
from collections import Counter
c = Counter(nums)
return [x for x, f in c.items() if f > 1]
# Complexity: O(n) time, O(n) space

18) Two Sum problem


def two_sum(nums, target):
idx = {}
for i, x in enumerate(nums):
if target - x in idx:
return idx[target - x], i
idx[x] = i
return None
# Complexity: O(n) time, O(n) space

19) Move zeroes to end


def move_zeroes(nums):
j = 0
for i, x in enumerate(nums):
if x != 0:
nums[j], nums[i] = nums[i], nums[j]
j += 1
return nums
# Complexity: O(n) time, O(1) space

20) Kadane’s algorithm (max subarray sum)


def max_subarray(nums):
best = curr = nums[0]
for x in nums[1:]:
curr = max(x, curr + x)
best = max(best, curr)
return best
# Complexity: O(n) time, O(1) space

21) Binary search


def binary_search(a, target):
l, r = 0, len(a) - 1
while l <= r:
m = (l + r) // 2
if a[m] == target:
return m
if a[m] < target:
l = m + 1
else:
r = m - 1
return -1
# Complexity: O(log n) time, O(1) space

22) Linear search


def linear_search(a, target):
for i, x in enumerate(a):
if x == target:
return i
return -1
# Complexity: O(n) time, O(1) space

23) Merge sort


def merge_sort(a):
if len(a) <= 1:
return a
mid = len(a)//2
left = merge_sort(a[:mid])
right = merge_sort(a[mid:])
return merge_sorted(left, right)
# Complexity: O(n log n) time, O(n) space

24) Quick sort (in-place)


def quick_sort(nums):
def part(l, r):
pivot = nums[r]
i = l
for j in range(l, r):
if nums[j] <= pivot:
nums[i], nums[j] = nums[j], nums[i]
i += 1
nums[i], nums[r] = nums[r], nums[i]
return i
def qs(l, r):
if l < r:
p = part(l, r)
qs(l, p-1); qs(p+1, r)
qs(0, len(nums)-1)
return nums
# Avg: O(n log n), worst: O(n^2); O(log n) space (stack)

25) Bubble sort


def bubble_sort(a):
n = len(a)
for i in range(n):
swapped = False
for j in range(0, n-i-1):
if a[j] > a[j+1]:
a[j], a[j+1] = a[j+1], a[j]
swapped = True
if not swapped: break
return a
# Complexity: O(n^2) time, O(1) space

26) Insertion sort


def insertion_sort(a):
for i in range(1, len(a)):
key = a[i]; j = i - 1
while j >= 0 and a[j] > key:
a[j+1] = a[j]; j -= 1
a[j+1] = key
return a
# Complexity: O(n^2) time, O(1) space

27) Stack implementation


class Stack:
def __init__(self):
self.data = []
def push(self, x): self.data.append(x)
def pop(self): return self.data.pop() if self.data else None
def peek(self): return self.data[-1] if self.data else None
def empty(self): return not self.data
# Operations: O(1) amortized
28) Queue implementation (deque)
from collections import deque
class Queue:
def __init__(self):
self.d = deque()
def enqueue(self, x): self.d.append(x)
def dequeue(self): return self.d.popleft() if self.d else None
def empty(self): return not self.d
# Operations: O(1) amortized

29) Queue using two stacks


class MyQueue:
def __init__(self):
self.s1, self.s2 = [], []
def enqueue(self, x):
self.s1.append(x)
def dequeue(self):
if not self.s2:
while self.s1:
self.s2.append(self.s1.pop())
return self.s2.pop() if self.s2 else None
# Amortized O(1) per op

30) Balanced parentheses


def is_balanced(s: str) -> bool:
pairs = {')':'(', ']':'[', '}':'{'}
stack = []
for ch in s:
if ch in '([{':
stack.append(ch)
elif ch in ')]}':
if not stack or stack[-1] != pairs[ch]:
return False
stack.pop()
return not stack
# Complexity: O(n) time, O(n) space

31) Reverse a linked list


class Node:
def __init__(self, val, nxt=None):
self.val, self.next = val, nxt
def reverse_list(head):
prev, curr = None, head
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
return prev
# Complexity: O(n) time, O(1) space

32) Detect cycle in linked list (Floyd)


def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
# Complexity: O(n) time, O(1) space

33) Middle element of linked list


def middle_node(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
# Complexity: O(n) time, O(1) space

34) Merge two sorted linked lists


def merge_lists(l1, l2):
dummy = tail = Node(0)
while l1 and l2:
if l1.val <= l2.val:
tail.next, l1 = l1, l1.next
else:
tail.next, l2 = l2, l2.next
tail = tail.next
tail.next = l1 or l2
return dummy.next
# Complexity: O(n+m) time, O(1) space
35) Remove duplicates in linked list (unsorted)
def remove_dups_linked(head):
seen = set()
prev, curr = None, head
while curr:
if curr.val in seen:
prev.next = curr.next
else:
seen.add(curr.val)
prev = curr
curr = curr.next
return head
# Complexity: O(n) time, O(n) space

36) Implement hash map using dict (demo)


# Python dict is a hash map; example frequency counter:
def freq_map(iterable):
d = {}
for x in iterable:
d[x] = d.get(x, 0) + 1
return d
# Avg O(1) per op

37) First non-repeating char in string


def first_unique_char(s: str) -> int:
from collections import Counter
c = Counter(s)
for i, ch in enumerate(s):
if c[ch] == 1:
return i
return -1
# Complexity: O(n) time, O(1) space (alphabet bounded) or O(n)

38) Count character frequency


def char_freq(s: str):
from collections import Counter
return dict(Counter(s))
# Complexity: O(n) time, O(k) space
39) Find intersection of two arrays
def intersection(a, b):
sa, sb = set(a), set(b)
return list(sa & sb)
# Complexity: O(n+m) time, O(n+m) space

40) Union of arrays


def union(a, b):
return list(set(a) | set(b))
# Complexity: O(n+m) time, O(n+m) space

41) Longest common prefix (strings)


def longest_common_prefix(strs):
if not strs:
return ''
shortest = min(strs, key=len)
for i, ch in enumerate(shortest):
for s in strs:
if s[i] != ch:
return shortest[:i]
return shortest
# Complexity: O(n * m) time, O(1) space

42) Longest palindromic substring (expand centers)


def longest_palindrome(s: str) -> str:
if not s: return ''
start, end = 0, 0
def expand(l, r):
while l >= 0 and r < len(s) and s[l] == s[r]:
l -= 1; r += 1
return l+1, r-1
for i in range(len(s)):
l1, r1 = expand(i, i)
l2, r2 = expand(i, i+1)
if r1 - l1 > end - start:
start, end = l1, r1
if r2 - l2 > end - start:
start, end = l2, r2
return s[start:end+1]
# Complexity: O(n^2) time, O(1) space

43) Tower of Hanoi (moves list)


def hanoi(n, src='A', aux='B', dst='C'):
moves = []
def move(k, a, b, c):
if k == 0: return
move(k-1, a, c, b)
moves.append((a, c))
move(k-1, b, a, c)
move(n, src, aux, dst)
return moves
# Complexity: O(2^n) time, O(n) space

44) Print all subsets of a set


def subsets(nums):
res = [[]]
for x in nums:
res += [curr + [x] for curr in res]
return res
# Complexity: O(n * 2^n) time, O(2^n) space

45) Binary tree traversal (inorder, preorder, postorder)


class TNode:
def __init__(self, val, left=None, right=None):
self.val, self.left, self.right = val, left, right

def inorder(root):
return inorder(root.left) + [root.val] + inorder(root.right) if root
else []

def preorder(root):
return [root.val] + preorder(root.left) + preorder(root.right) if
root else []

def postorder(root):
return postorder(root.left) + postorder(root.right) + [root.val] if
root else []
# Complexity: O(n) time, O(h) stack
46) Height of binary tree
def height(root):
if not root: return -1 # edges height; use 0 for nodes height
return 1 + max(height(root.left), height(root.right))
# Complexity: O(n) time, O(h) space

47) Lowest common ancestor (BST)


def lca_bst(root, p, q):
cur = root
while cur:
if p.val < cur.val and q.val < cur.val:
cur = cur.left
elif p.val > cur.val and q.val > cur.val:
cur = cur.right
else:
return cur
# Complexity: O(h) time, O(1) space

48) Graph using adjacency list


def build_graph(edges, directed=False):
g = {}
for u, v in edges:
g.setdefault(u, []).append(v)
if not directed:
g.setdefault(v, []).append(u)
return g
# Complexity: O(V+E)

49) BFS traversal


from collections import deque
def bfs(graph, start):
visited, order = set([start]), []
q = deque([start])
while q:
u = q.popleft()
order.append(u)
for v in graph.get(u, []):
if v not in visited:
visited.add(v); q.append(v)
return order
# Complexity: O(V+E) time, O(V) space
50) DFS traversal
def dfs(graph, start):
visited, order = set(), []
def rec(u):
visited.add(u); order.append(u)
for v in graph.get(u, []):
if v not in visited:
rec(v)
rec(start)
return order
# Complexity: O(V+E) time, O(V) space

You might also like