Python Interview Master Notebook 230 Questions
Python Interview Master Notebook 230 Questions
Write a Python program that takes an integer input and determines whether
the number
**Logic:**
is even or odd. Explain why the modulo operator works for this check and discuss
behavior for zero and negative numbers.
**Logic:**
Explain why this works in Python.
a, b = 5, 10
a, b = b, a
print(a, b)
**Logic:**
Handle edge cases and justify the time complexity.
print(is_prime(29))
**Logic:**
Explain base case and recursive step.
**Logic:**
Explain why iteration is preferred over recursion here.
print(fibonacci(10))
**Logic:**
Explain the Gregorian calendar rules involved.
print(is_leap_year(2024))
**Logic:**
Explain what defines an Armstrong number.
**Logic:**
print(reverse_int(-12345))
print(sum_of_digits(123))
### 10. Compute the greatest common divisor (GCD) of two integers using
Euclid’s algorithm.
**Logic:**
print(gcd(48, 18))
### 11. Compute the sum of numbers from 1 to N using a single Python
expression.
**Logic:**
N = 100
print(sum(range(1, N + 1)))
### 12. Demonstrate how to create an infinite loop and explain safe termination.
**Logic:**
while True:
pass # Stop using KeyboardInterrupt (Ctrl+C)
### 13. Explain the difference between 'break' and 'continue' statements using
examples.
**Logic:**
def c_to_f(c):
return (c * 9 / 5) + 32
print(c_to_f(25))
**Logic:**
**Logic:**
**Logic:**
x = 3.14
print(type(x))
### 18. Find the largest among three numbers without using conditional
statements.
**Logic:**
**Logic:**
import random
print([Link](1, 100))
**Logic:**
s = "Python"
print(s[::-1])
**Logic:**
print(is_palindrome("madam"))
**Logic:**
### 24. Check whether two strings are anagrams of each other.
**Logic:**
print(are_anagrams("listen", "silent"))
### 25. Remove duplicate characters from a string while preserving order.
**Logic:**
print(remove_duplicates("hello"))
**Logic:**
If no such character exists, return None.
Discuss the time and space complexity of your approach.
print(first_non_repeating("swiss"))
### 27. Split a sentence into words and return them as a list.
**Logic:**
Explain how Python handles whitespace by default.
### 28. Join a list of words into a single string separated by spaces.
**Logic:**
Explain why join is preferred over string concatenation in loops.
### 29. Check whether a given string represents a valid non-negative integer.
**Logic:**
Explain the limitations of [Link]().
print(is_numeric("123"))
print(is_numeric("-123"))
### 30. Replace all occurrences of a character in a string with another character.
**Logic:**
Explain why strings are immutable in Python.
s = "hello"
print([Link]("l", "z"))
**Logic:**
Ignore digits, spaces, and special characters.
print(count_vowels_consonants("Hello World"))
**Logic:**
If multiple words have the same maximum length, return the first one.
**Logic:**
Explain how swapcase works internally.
s = "PyThOn"
print([Link]())
### 34. Check whether a string starts with a given prefix and ends with a given
suffix.
**Logic:**
s = "HelloWorld"
print([Link]("Hello"), [Link]("World"))
**Logic:**
Discuss the time complexity.
print(all_substrings("abc"))
**Logic:**
Explain the difference between strip, lstrip, and rstrip.
**Logic:**
Explain a real-world limitation of [Link]().
**Logic:**
Explain naming rules briefly.
print("var_1".isidentifier())
print("1var".isidentifier())
**Logic:**
Explain the time complexity.
nums = [4, 1, 9, 2]
print(max(nums), min(nums))
**Logic:**
Handle edge cases where it may not exist.
def second_largest(nums):
unique = sorted(set(nums))
if len(unique) < 2:
raise ValueError("Second largest element does not exist")
return unique[-2]
### 41. Remove duplicate elements from a list while preserving order.
**Logic:**
Explain why set alone is insufficient.
def remove_duplicates(lst):
seen = set()
result = []
for x in lst:
if x not in seen:
[Link](x)
[Link](x)
return result
print(remove_duplicates([1, 2, 2, 3, 1]))
### 42. Sort a list without using the built-in sort() or sorted() functions.
**Logic:**
Explain the algorithm used.
def bubble_sort(lst):
n = len(lst)
for i in range(n):
for j in range(0, n - i - 1):
if lst[j] > lst[j + 1]:
lst[j], lst[j + 1] = lst[j + 1], lst[j]
return lst
print(bubble_sort([3, 1, 2]))
**Logic:**
Explain how in-place operations save memory.
lst = [1, 2, 3]
[Link]()
print(lst)
### 44. Merge two sorted lists into a single sorted list.
**Logic:**
Discuss time complexity.
**Logic:**
Explain how sets improve performance.
a = [1, 2, 3]
b = [2, 3, 4]
print(list(set(a) & set(b)))
### 46. Generate a list of squares of numbers from 0 to N-1 using list
comprehension.
**Logic:**
N = 5
print([x ** 2 for x in range(N)])
**Logic:**
Explain limitations of this approach for deeper nesting.
**Logic:**
Explain why this operation mutates the list.
import random
lst = [1, 2, 3, 4]
[Link](lst)
print(lst)
**Logic:**
Explain why sum is preferred over manual loops.
nums = [1, 2, 3, 4]
print(sum(nums))
**Logic:**
Explain Pythonic ways to do this.
lst = []
if not lst:
print("List is empty")
**Logic:**
Explain why using the built-in sum() function is preferred over manual loops.
nums = [1, 2, 3, 4]
print(sum(nums))
**Logic:**
Explain the Pythonic way of doing this.
lst = []
if not lst:
print("List is empty")
**Logic:**
Discuss the time complexity.
nums = [1, 2, 2, 3, 2]
print([Link](2))
**Logic:**
Handle cases where the list size is not a multiple of k.
**Logic:**
Demonstrate with examples.
lst = [1]
[Link]([2, 3])
print(lst)
lst = [1]
[Link]([2, 3])
print(lst)
### 57. Remove the N-th element from a list using index-based deletion.
**Logic:**
Explain what happens if the index is invalid.
**Logic:**
Handle cases where k is greater than the list length.
**Logic:**
Explain the difference between equality (==) and identity (is).
a = [1, 2]
b = [1, 2]
print(a == b)
print(a is b)
### 60. Generate all prime numbers up to N using the Sieve of Eratosthenes.
**Logic:**
Explain the algorithm briefly.
def sieve(n):
if n < 2:
return []
primes = [True] * (n + 1)
primes[0] = primes[1] = False
for p in range(2, int(n ** 0.5) + 1):
if primes[p]:
for i in range(p * p, n + 1, p):
primes[i] = False
return [i for i in range(2, n + 1) if primes[i]]
print(sieve(20))
**Logic:**
Explain the output type.
d1 = {"a": 1}
d2 = {"b": 2}
merged = {**d1, **d2}
print(merged)
**Logic:**
Explain why items() is preferred.
d = {"a": 1, "b": 2}
for key, value in [Link]():
print(key, value)
**Logic:**
Explain the time complexity.
d = {"a": 1, "b": 2}
print("a" in d)
**Logic:**
Explain how to avoid KeyError.
d = {"a": 1}
[Link]("a", None)
print(d)
**Logic:**
Explain its advantage over normal dictionaries.
d = defaultdict(int)
d["count"] += 1
print(d)
### 67. Create a dictionary from two lists: one of keys and one of values.
**Logic:**
Explain what happens if lengths differ.
**Logic:**
Explain how sets improve performance.
s1 = {1, 2, 3}
s2 = {2, 3, 4}
print(s1 & s2)
**Logic:**
Explain why order is not preserved.
nums = [1, 1, 2, 3]
print(list(set(nums)))
**Logic:**
Ignore case and punctuation.
import string
def word_frequency(sentence):
freq = {}
for word in [Link]().split():
word = [Link]([Link])
freq[word] = [Link](word, 0) + 1
return freq
### 71. Explain the difference between a set and a dictionary in Python.
**Logic:**
Focus on structure, usage, and constraints.
**Logic:**
Explain the returned object type.
d = {"a": 1, "b": 2}
print(list([Link]()))
**Logic:**
Provide an example.
**Logic:**
Explain the difference between clear() and reassigning.
s = {1, 2, 3}
[Link]()
print(s)
**Logic:**
Explain a real-world use case.
a = {1, 2, 3}
b = {2}
print(a - b)
**Logic:**
Explain how objects are created from a class.
class Dog:
def bark(self):
return "Woof"
d = Dog()
print([Link]())
### 77. Demonstrate single inheritance in Python.
**Logic:**
Explain how method resolution works in this case.
class Animal:
def speak(self):
return "Sound"
class Dog(Animal):
pass
d = Dog()
print([Link]())
**Logic:**
Demonstrate initialization of instance variables.
class Person:
def __init__(self, name, age):
[Link] = name
[Link] = age
p = Person("Alice", 30)
print([Link], [Link])
**Logic:**
Why is it required?
**Logic:**
with an example.
class Counter:
count = 0 # class variable
def __init__(self):
[Link] += 1
[Link] = [Link] # instance variable
a = Counter()
b = Counter()
print([Link], [Link], [Link])
### 81. Explain how Python handles private variables.
**Logic:**
Demonstrate name mangling with an example.
class A:
def __init__(self):
self.__x = 10 # name-mangled to _A__x
a = A()
print(a._A__x)
**Logic:**
Explain how decorators modify function behavior.
def my_decorator(func):
def wrapper():
print("Before function")
func()
print("After function")
return wrapper
@my_decorator
def say_hello():
print("Hello")
say_hello()
**Logic:**
Write a generator function and show how it is consumed.
def simple_generator():
for i in range(3):
yield i
**Logic:**
Provide an example and a limitation.
add = lambda x, y: x + y
print(add(2, 3))
### 85. Demonstrate exception handling using try, except, and finally.
**Logic:**
Explain the role of each block.
try:
x = 1 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
finally:
print("Execution completed")
**Logic:**
Demonstrate modifying a global variable inside a function.
x = 10
def modify():
global x
x = 20
modify()
print(x)
**Logic:**
Explain why using 'with' is preferred.
**Logic:**
Provide a simple example.
**Logic:**
**Logic:**
Provide examples.
import copy
a[0][0] = 99
print(b) # affected
print(c) # not affected
**Logic:**
Explain time complexity.
**Logic:**
Explain what happens if lengths differ.
**Logic:**
Explain the logic behind spacing and star count.
n = 5
for i in range(n):
print(" " * (n - i - 1) + "*" * (2 * i + 1))
### 94. Find the missing number from an array containing numbers from 1 to N.
**Logic:**
Explain the mathematical approach.
**Logic:**
Provide a real-world example.
**Logic:**
Explain the format string.
dt = [Link]("2024-01-01", "%Y-%m-%d")
print(dt)
**Logic:**
Explain the logic.
**Logic:**
Explain why this is useful.
import os
print([Link]())
### 99. Check whether parentheses in a string are balanced.
**Logic:**
Explain stack usage.
def is_balanced(s):
stack = []
mapping = {')': '(', '}': '{', ']': '['}
for ch in s:
if ch in [Link]():
[Link](ch)
elif ch in mapping:
if not stack or [Link]() != mapping[ch]:
return False
return not stack
print(is_balanced("()[]{}"))
**Logic:**
Explain why precise benchmarking is hard.
import time
start = [Link]()
[Link](1)
end = [Link]()
print(end - start)
### 101. Given an array of integers and a target value, return the indices of the
two numbers
**Logic:**
such that they add up to the target.
Assume exactly one solution exists and the same element cannot be used twice.
Explain the time and space complexity.
### 102. Given an array where each element represents the price of a stock on a
given day,
**Logic:**
find the maximum profit you can achieve by buying once and selling once.
Explain why a greedy approach works.
def max_profit(prices):
min_price = float('inf')
profit = 0
for price in prices:
min_price = min(min_price, price)
profit = max(profit, price - min_price)
return profit
print(max_profit([7, 1, 5, 3, 6, 4]))
### 103. Given an array of integers, return an array such that each element is the
product
**Logic:**
of all elements except itself.
Do this without using division.
def product_except_self(nums):
n = len(nums)
res = [1] * n
prefix = 1
for i in range(n):
res[i] = prefix
prefix *= nums[i]
postfix = 1
for i in range(n - 1, -1, -1):
res[i] *= postfix
postfix *= nums[i]
return res
print(product_except_self([1, 2, 3, 4]))
### 104. Given an array representing heights of vertical lines, find two lines that
together
**Logic:**
with the x-axis form a container holding the most water.
Explain the two-pointer strategy.
def max_area(height):
left, right = 0, len(height) - 1
max_water = 0
### 105. Given an integer array nums, return all unique triplets [nums[i], nums[j],
nums[k]]
**Logic:**
such that i != j != k and nums[i] + nums[j] + nums[k] == 0.
Explain how sorting helps.
def three_sum(nums):
[Link]()
res = []
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i - 1]:
continue
left, right = i + 1, len(nums) - 1
while left < right:
s = nums[i] + nums[left] + nums[right]
if s == 0:
[Link]([nums[i], nums[left], nums[right]])
left += 1
while left < right and nums[left] == nums[left - 1]:
left += 1
elif s < 0:
left += 1
else:
right -= 1
return res
print(three_sum([-1,0,1,2,-1,-4]))
### 106. Find the contiguous subarray with the maximum sum.
**Logic:**
Explain Kadane’s algorithm.
def max_subarray(nums):
current_sum = nums[0]
max_sum = nums[0]
return max_sum
print(max_subarray([-2,1,-3,4,-1,2,1,-5,4]))
**Logic:**
Explain the transformation steps.
def rotate_matrix(matrix):
[Link]()
for i in range(len(matrix)):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
m = [[1,2,3],[4,5,6],[7,8,9]]
rotate_matrix(m)
print(m)
**Logic:**
Explain the boundary shrinking technique.
def spiral_order(matrix):
res = []
while matrix:
res += [Link](0)
matrix = list(zip(*matrix))[::-1]
return res
print(spiral_order([[1,2,3],[4,5,6],[7,8,9]]))
**Logic:**
Explain how binary search is adapted.
return -1
print(search_rotated([4,5,6,7,0,1,2], 0))
**Logic:**
Explain why sorting by start time is necessary.
def merge_intervals(intervals):
[Link](key=lambda x: x[0])
merged = [intervals[0]]
for start, end in intervals[1:]:
last_end = merged[-1][1]
if start <= last_end:
merged[-1][1] = max(last_end, end)
else:
[Link]([start, end])
return merged
print(merge_intervals([[1,3],[2,6],[8,10],[15,18]]))
### 111. Insert a new interval into a list of non-overlapping intervals and merge if
necessary.
**Logic:**
print(insert_interval([[1,3],[6,9]], [2,5]))
### 112. Find the length of the longest consecutive sequence in an unsorted array.
**Logic:**
Explain why a set is used.
def longest_consecutive(nums):
num_set = set(nums)
longest = 0
return longest
print(longest_consecutive([100,4,200,1,3,2]))
### 113. Move all zeroes in an array to the end while maintaining the order of
non-zero elements.
**Logic:**
Explain the two-pointer approach.
def move_zeroes(nums):
pos = 0
for i in range(len(nums)):
if nums[i] != 0:
nums[pos], nums[i] = nums[i], nums[pos]
pos += 1
nums = [0,1,0,3,12]
move_zeroes(nums)
print(nums)
### 114. Find the duplicate number in an array containing n+1 integers
**Logic:**
where each integer is between 1 and n.
Explain Floyd’s cycle detection.
def find_duplicate(nums):
slow = fast = 0
while True:
slow = nums[slow]
fast = nums[nums[fast]]
if slow == fast:
break
slow2 = 0
while slow != slow2:
slow = nums[slow]
slow2 = nums[slow2]
return slow
print(find_duplicate([1,3,4,2,2]))
### 115. Find the total number of continuous subarrays whose sum equals k.
**Logic:**
Explain prefix sum usage.
return count
print(subarray_sum([1,1,1], 2))
### 116. Find the maximum value in each sliding window of size k.
**Logic:**
Explain why a deque is used.
return res
print(max_sliding_window([1,3,-1,-3,5,3,6,7], 3))
### 117. Given an elevation map, compute how much water it can trap after
raining.
**Logic:**
Explain the two-pointer approach.
def trap_rain_water(height):
left, right = 0, len(height) - 1
left_max = right_max = 0
water = 0
return water
print(trap_rain_water([0,1,0,2,1,0,1,3,2,1,2,1]))
### 118. Find the smallest missing positive integer in an unsorted array.
**Logic:**
Explain why in-place hashing works.
def first_missing_positive(nums):
n = len(nums)
for i in range(n):
while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
for i in range(n):
if nums[i] != i + 1:
return i + 1
return n + 1
print(first_missing_positive([3,4,-1,1]))
### 119. Sort an array containing only 0s, 1s, and 2s without using sorting.
**Logic:**
Explain the Dutch National Flag algorithm.
def sort_colors(nums):
left, right, i = 0, len(nums) - 1, 0
while i <= right:
if nums[i] == 0:
nums[left], nums[i] = nums[i], nums[left]
left += 1
elif nums[i] == 2:
nums[right], nums[i] = nums[i], nums[right]
right -= 1
i -= 1
i += 1
nums = [2,0,2,1,1,0]
sort_colors(nums)
print(nums)
**Logic:**
Explain the binary search partition approach.
while True:
i = (left + right) // 2
j = half - i
print(find_median_sorted_arrays([1,3], [2]))
### 121. Reverse a singly linked list.
**Logic:**
Explain pointer manipulation.
**Logic:**
Explain iterative vs recursive approaches.
**Logic:**
Explain the steps involved.
### 124. Remove the N-th node from the end of a linked list.
**Logic:**
Explain the two-pointer technique.
**Logic:**
Explain Floyd’s cycle detection algorithm.
### 126. Define a binary tree and explain the role of a TreeNode.
**Logic:**
Write the basic TreeNode class used in most interview problems.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
**Logic:**
Explain why recursion naturally fits tree traversal.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def inorder(root):
if not root:
return []
return inorder([Link]) + [[Link]] + inorder([Link])
**Logic:**
Explain the traversal order.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def preorder(root):
if not root:
return []
return [[Link]] + preorder([Link]) + preorder([Link])
**Logic:**
Explain a real-world use case.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def postorder(root):
if not root:
return []
return postorder([Link]) + postorder([Link]) + [[Link]]
### 130. Implement level-order traversal (BFS) of a binary tree.
**Logic:**
Explain why a queue is required.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def level_order(root):
if not root:
return []
q = deque([root])
res = []
while q:
node = [Link]()
[Link]([Link])
if [Link]:
[Link]([Link])
if [Link]:
[Link]([Link])
return res
**Logic:**
Explain the recursive relation.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def max_depth(root):
if not root:
return 0
return 1 + max(max_depth([Link]), max_depth([Link]))
**Logic:**
Explain the base and recursive cases.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
**Logic:**
Explain how mirroring is used.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def is_symmetric(root):
def mirror(a, b):
if not a and not b:
return True
if not a or not b:
return False
return (
[Link] == [Link] and
mirror([Link], [Link]) and
mirror([Link], [Link])
)
return mirror([Link], [Link]) if root else True
**Logic:**
Explain how recursion swaps subtrees.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def invert_tree(root):
if root:
[Link], [Link] = invert_tree([Link]), invert_tree([Link])
return root
**Logic:**
Explain why height computation is combined with checking.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def is_balanced(root):
def check(node):
if not node:
return 0
left = check([Link])
if left == -1:
return -1
right = check([Link])
if right == -1 or abs(left - right) > 1:
return -1
return 1 + max(left, right)
return check(root) != -1
### 136. Validate whether a binary tree is a binary search tree (BST).
**Logic:**
Explain the min-max constraint approach.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
### 137. Find the lowest common ancestor (LCA) of two nodes in a BST.
**Logic:**
Explain how BST properties simplify the solution.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
**Logic:**
Explain why depth and diameter are computed together.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def diameter(root):
ans = 0
def depth(node):
nonlocal ans
if not node:
return 0
left = depth([Link])
right = depth([Link])
ans = max(ans, left + right)
return 1 + max(left, right)
depth(root)
return ans
**Logic:**
Explain DFS usage.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
**Logic:**
Explain backtracking.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def binary_tree_paths(root):
res = []
def dfs(node, path):
if not node:
return
[Link](str([Link]))
if not [Link] and not [Link]:
[Link]("->".join(path))
else:
dfs([Link], path)
dfs([Link], path)
[Link]()
dfs(root, [])
return res
**Logic:**
Explain why BFS is preferred.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def min_depth(root):
if not root:
return 0
q = deque([(root, 1)])
while q:
node, depth = [Link]()
if not [Link] and not [Link]:
return depth
if [Link]:
[Link](([Link], depth + 1))
if [Link]:
[Link](([Link], depth + 1))
**Logic:**
Explain preorder traversal usage.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def flatten(root):
def dfs(node):
if not node:
return None
left_tail = dfs([Link])
right_tail = dfs([Link])
if left_tail:
left_tail.right = [Link]
[Link] = [Link]
[Link] = None
return right_tail or left_tail or node
dfs(root)
**Logic:**
Explain why preorder traversal is commonly used.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def serialize(root):
vals = []
def dfs(node):
if not node:
[Link]('#')
return
[Link](str([Link]))
dfs([Link])
dfs([Link])
dfs(root)
return ','.join(vals)
def deserialize(data):
vals = iter([Link](','))
def dfs():
v = next(vals)
if v == '#':
return None
node = TreeNode(int(v))
[Link] = dfs()
[Link] = dfs()
return node
return dfs()
**Logic:**
Explain the height-based optimization.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def count_nodes(root):
def left_height(node):
h = 0
while node:
h += 1
node = [Link]
return h
def right_height(node):
h = 0
while node:
h += 1
node = [Link]
return h
if not root:
return 0
lh, rh = left_height(root), right_height(root)
if lh == rh:
return (1 << lh) - 1
return 1 + count_nodes([Link]) + count_nodes([Link])
### 145. Construct a binary tree from preorder and inorder traversal arrays.
**Logic:**
Explain how recursion splits the tree.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
**Logic:**
How can deep recursion be handled safely?
**Logic:**
Explain divide-and-conquer.
**Logic:**
@lru_cache(None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
**Logic:**
Explain why the middle element is chosen.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
[Link] = val
[Link] = left
[Link] = right
def sorted_array_to_bst(nums):
if not nums:
return None
mid = len(nums) // 2
root = TreeNode(nums[mid])
[Link] = sorted_array_to_bst(nums[:mid])
[Link] = sorted_array_to_bst(nums[mid+1:])
return root
### 150. Explain tail recursion and whether Python optimizes it.
**Logic:**
# Tail recursion occurs when the recursive call is the last operation.
# Python does NOT perform tail-call optimization.
### 151. Explain what a graph is and list common ways to represent a graph in
Python.
**Logic:**
Discuss adjacency list vs adjacency matrix.
# Graph representations:
# 1. Adjacency List: dict {node: [neighbors]} – space efficient for sparse graphs
# 2. Adjacency Matrix: 2D list – fast edge lookup, high space cost
### 152. Implement Depth-First Search (DFS) for a graph using recursion.
**Logic:**
Explain visited set usage.
**Logic:**
Explain why a queue is required.
while q:
node = [Link]()
[Link](node)
for neigh in [Link](node, []):
if neigh not in visited:
[Link](neigh)
[Link](neigh)
return order
**Logic:**
Explain parent tracking.
def has_cycle_undirected(graph):
visited = set()
**Logic:**
Explain recursion stack usage.
def has_cycle_directed(graph):
visited, rec = set(), set()
def dfs(node):
[Link](node)
[Link](node)
for neigh in [Link](node, []):
if neigh not in visited:
if dfs(neigh):
return True
elif neigh in rec:
return True
[Link](node)
return False
**Logic:**
Explain why DFS/BFS works.
def count_components(graph):
visited = set()
count = 0
def dfs(node):
[Link](node)
for neigh in [Link](node, []):
if neigh not in visited:
dfs(neigh)
### 157. Perform topological sorting of a directed acyclic graph using DFS.
**Logic:**
Explain post-order processing.
def topo_sort(graph):
visited = set()
stack = []
def dfs(node):
[Link](node)
for neigh in [Link](node, []):
if neigh not in visited:
dfs(neigh)
[Link](node)
return stack[::-1]
def topo_kahn(graph):
indeg = {u: 0 for u in graph}
for u in graph:
for v in graph[u]:
indeg[v] += 1
while q:
u = [Link]()
[Link](u)
for v in graph[u]:
indeg[v] -= 1
if indeg[v] == 0:
[Link](v)
return res
### 159. Find the shortest path in an unweighted graph using BFS.
**Logic:**
Explain why BFS guarantees shortest path.
while q:
node, path = [Link]()
if node == end:
return path
for neigh in [Link](node, []):
if neigh not in visited:
[Link](neigh)
[Link]((neigh, path + [neigh]))
return None
**Logic:**
Explain graph coloring.
def is_bipartite(graph):
color = {}
**Logic:**
List its main operations.
# Operations:
# find(x): find representative
# union(x, y): merge sets
# Used in cycle detection, Kruskal's MST
**Logic:**
Explain how it improves performance.
class UnionFind:
def __init__(self, n):
[Link] = list(range(n))
**Logic:**
Explain why this works.
### 164. Find the minimum spanning tree using Kruskal’s algorithm.
**Logic:**
Explain edge sorting.
def kruskal(edges, n):
uf = UnionFind(n)
mst = []
[Link](key=lambda x: x[2])
for u, v, w in edges:
if [Link](u) != [Link](v):
[Link](u, v)
[Link]((u, v, w))
return mst
**Logic:**
Mention its limitation.
**Logic:**
import heapq
while pq:
d, u = [Link](pq)
if d > dist[u]:
continue
for v, w in graph[u]:
if dist[v] > d + w:
dist[v] = d + w
[Link](pq, (dist[v], v))
return dist
**Logic:**
Explain when it is preferred over Dijkstra.
**Logic:**
def has_negative_cycle(edges, n):
dist = [0] * n
for _ in range(n - 1):
for u, v, w in edges:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
for u, v, w in edges:
if dist[u] + w < dist[v]:
return True
return False
**Logic:**
Discuss time complexity.
**Logic:**
def floyd_warshall(dist):
n = len(dist)
for k in range(n):
for i in range(n):
for j in range(n):
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
**Logic:**
Explain cycle detection in directed graph.
**Logic:**
Explain DFS coloring.
def eventual_safe_nodes(graph):
n = len(graph)
color = [0] * n # 0=unvisited,1=visiting,2=safe
def dfs(u):
if color[u]:
return color[u] == 2
color[u] = 1
for v in graph[u]:
if not dfs(v):
return False
color[u] = 2
return True
**Logic:**
Explain hashmap usage.
**Logic:**
Explain graph pruning.
### 175. Explain why graphs are harder than trees in interviews.
**Logic:**
**Logic:**
Differentiate between top-down and bottom-up approaches.
### 177. Compute the N-th Fibonacci number using Dynamic Programming.
**Logic:**
Explain why DP improves over naive recursion.
def fib(n):
if n < 2:
return n
dp = [0, 1]
for i in range(2, n + 1):
[Link](dp[i-1] + dp[i-2])
return dp[n]
print(fib(10))
**Logic:**
Given coin denominations and an amount, return the minimum number of coins needed.
print(coin_change([1,2,5], 11))
**Logic:**
Explain time complexity.
def length_of_lis(nums):
dp = [1] * len(nums)
for i in range(len(nums)):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
print(length_of_lis([10,9,2,5,3,7,101,18]))
### 180. Solve the 0/1 Knapsack problem using Dynamic Programming.
**Logic:**
Explain table construction.
**Logic:**
Explain the recurrence relation.
def rob(nums):
if not nums:
return 0
if len(nums) == 1:
return nums[0]
dp1, dp2 = 0, 0
for num in nums:
dp1, dp2 = dp2, max(dp2, dp1 + num)
return dp2
print(rob([2,7,9,3,1]))
**Logic:**
Explain why greedy fails.
print(lcs("abcde", "ace"))
**Logic:**
Explain allowed operations.
print(edit_distance("horse", "ros"))
**Logic:**
Explain optimal substructure.
**Logic:**
Explain relation to Fibonacci.
def climb_stairs(n):
a, b = 1, 1
for _ in range(n):
a, b = b, a + b
return a
print(climb_stairs(5))
**Logic:**
Provide an example where greedy works.
**Logic:**
Explain greedy choice.
def activity_selection(intervals):
[Link](key=lambda x: x[1])
res = [intervals[0]]
for s, e in intervals[1:]:
if s >= res[-1][1]:
[Link]((s, e))
return res
print(activity_selection([(1,3),(2,4),(3,5),(0,6)]))
### 188. Solve the N-Queens problem.
**Logic:**
Explain backtracking.
def solve_n_queens(n):
res = []
cols, diag1, diag2 = set(), set(), set()
backtrack(0, [])
return res
print(len(solve_n_queens(4)))
**Logic:**
Explain time complexity.
def permutations(nums):
res = []
def backtrack(path, remaining):
if not remaining:
[Link](path)
return
for i in range(len(remaining)):
backtrack(path + [remaining[i]], remaining[:i] + remaining[i+1:])
backtrack([], nums)
return res
print(permutations([1,2,3]))
**Logic:**
Explain bitmask vs backtracking.
def subsets(nums):
res = [[]]
for num in nums:
res += [curr + [num] for curr in res]
return res
print(subsets([1,2,3]))
def count_bits(n):
count = 0
while n:
n &= n - 1
count += 1
return count
print(count_bits(15))
**Logic:**
Explain bitwise logic.
def is_power_of_two(n):
return n > 0 and (n & (n - 1)) == 0
print(is_power_of_two(16))
### 193. Find the single number in an array where every element appears twice
except one.
**Logic:**
Explain XOR usage.
def single_number(nums):
res = 0
for n in nums:
res ^= n
return res
print(single_number([4,1,2,1,2]))
**Logic:**
Explain shifting.
def reverse_bits(n):
res = 0
for _ in range(32):
res = (res << 1) | (n & 1)
n >>= 1
return res
**Logic:**
**Logic:**
**Logic:**
**Logic:**
**Logic:**
### 201. Given an array of integers and a target value, return the indices of the
two numbers
**Logic:**
such that they add up to the target.
Explain why a hash-map based solution is optimal.
### 202. Check whether two strings are anagrams of each other.
**Logic:**
Explain why character frequency comparison works.
### 203. Find the contiguous subarray with the maximum sum.
**Logic:**
Explain Kadane’s Algorithm and why resetting the sum is valid.
def max_subarray(nums):
best = nums[0]
current = 0
for n in nums:
current = max(n, current + n)
best = max(best, current)
return best
### 204. Return an array where each index contains the product of all numbers
**Logic:**
except itself, without using division.
def product_except_self(nums):
res = [1] * len(nums)
prefix = 1
for i in range(len(nums)):
res[i] = prefix
prefix *= nums[i]
postfix = 1
for i in range(len(nums)-1, -1, -1):
res[i] *= postfix
postfix *= nums[i]
return res
**Logic:**
Explain why a stack is required.
def is_valid_parentheses(s):
stack = []
pairs = {')': '(', ']': '[', '}': '{'}
for c in s:
if c in pairs:
if not stack or [Link]() != pairs[c]:
return False
else:
[Link](c)
return not stack
### 206. Find the maximum profit achievable from a single stock buy-sell
transaction.
**Logic:**
Explain the greedy choice.
def max_profit(prices):
min_price = float('inf')
profit = 0
for p in prices:
min_price = min(min_price, p)
profit = max(profit, p - min_price)
return profit
### 207. Find the length of the longest substring without repeating characters.
**Logic:**
Explain the sliding window invariant.
def longest_unique_substring(s):
seen = set()
l = 0
best = 0
for r in range(len(s)):
while s[r] in seen:
[Link](s[l])
l += 1
[Link](s[r])
best = max(best, r - l + 1)
return best
### 208. Find two vertical lines that form a container holding the maximum water.
**Logic:**
Explain why the two-pointer strategy is optimal.
def max_area(height):
l, r = 0, len(height) - 1
best = 0
while l < r:
best = max(best, (r - l) * min(height[l], height[r]))
if height[l] < height[r]:
l += 1
else:
r -= 1
return best
### 209. Find all unique triplets in an array that sum to zero.
**Logic:**
Explain duplicate elimination.
def three_sum(nums):
[Link]()
res = []
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i-1]:
continue
l, r = i+1, len(nums)-1
while l < r:
s = nums[i] + nums[l] + nums[r]
if s == 0:
[Link]([nums[i], nums[l], nums[r]])
l += 1
while l < r and nums[l] == nums[l-1]:
l += 1
elif s < 0:
l += 1
else:
r -= 1
return res
**Logic:**
Explain why sorting is mandatory.
def merge_intervals(intervals):
[Link](key=lambda x: x[0])
merged = [intervals[0]]
for s, e in intervals[1:]:
if s <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], e)
else:
[Link]([s, e])
return merged
def reverse_list(head):
prev, curr = None, head
while curr:
nxt = [Link]
[Link] = prev
prev = curr
curr = nxt
return prev
**Logic:**
Explain Floyd’s Tortoise and Hare algorithm.
def has_cycle(head):
slow = fast = head
while fast and [Link]:
slow = [Link]
fast = [Link]
if slow == fast:
return True
return False
**Logic:**
Explain dummy node usage.
**Logic:**
Explain subtree swapping.
def invert_tree(root):
if root:
[Link], [Link] = invert_tree([Link]), invert_tree([Link])
return root
### 215. Find the maximum depth of a binary tree.
**Logic:**
Explain recursive height calculation.
def max_depth(root):
if not root:
return 0
return 1 + max(max_depth([Link]), max_depth([Link]))
**Logic:**
Explain DFS flooding.
def num_islands(grid):
rows, cols = len(grid), len(grid[0])
def dfs(r, c):
if r<0 or c<0 or r>=rows or c>=cols or grid[r][c] != '1':
return
grid[r][c] = '0'
dfs(r+1,c); dfs(r-1,c); dfs(r,c+1); dfs(r,c-1)
count = 0
for r in range(rows):
for c in range(cols):
if grid[r][c] == '1':
dfs(r,c)
count += 1
return count
### 217. Find the lowest common ancestor of two nodes in a BST.
**Logic:**
Explain BST ordering property.
**Logic:**
Explain Fibonacci relation.
def climb_stairs(n):
a, b = 1, 1
for _ in range(n):
a, b = b, a+b
return a
**Logic:**
Explain optimal substructure.
def rob(nums):
prev, curr = 0, 0
for n in nums:
prev, curr = curr, max(curr, prev + n)
return curr
**Logic:**
Explain expand-around-center approach.
def longest_palindrome(s):
res = ""
for i in range(len(s)):
for l, r in [(i,i),(i,i+1)]:
while l>=0 and r<len(s) and s[l]==s[r]:
if r-l+1 > len(res):
res = s[l:r+1]
l-=1; r+=1
return res
**Logic:**
Explain termination condition.
**Logic:**
Explain pivot logic.
def find_min(nums):
l, r = 0, len(nums)-1
while l < r:
m = (l+r)//2
if nums[m] > nums[r]:
l = m+1
else:
r = m
return nums[l]
**Logic:**
Explain why heap size is limited.
import heapq
def kth_largest(nums, k):
h = []
for n in nums:
[Link](h, n)
if len(h) > k:
[Link](h)
return h[0]
**Logic:**
Explain recursion depth.
def flatten(lst):
res = []
for x in lst:
if isinstance(x, list):
[Link](flatten(x))
else:
[Link](x)
return res
**Logic:**
Explain square-root optimization.
def is_prime(n):
if n <= 1:
return False
for i in range(2, int(n**0.5)+1):
if n % i == 0:
return False
return True
**Logic:**
Explain [Link] usage.
import time, functools
def timer(func):
@[Link](func)
def wrapper(*args, **kwargs):
start = [Link]()
result = func(*args, **kwargs)
print([Link]() - start)
return result
return wrapper
**Logic:**
Explain why OrderedDict works.
class LRUCache:
def __init__(self, capacity):
[Link] = OrderedDict()
[Link] = capacity
**Logic:**
Explain delimiter safety.
def encode(strs):
return ''.join(f'{len(s)}#{s}' for s in strs)
def decode(s):
res, i = [], 0
while i < len(s):
j = i
while s[j] != '#':
j += 1
length = int(s[i:j])
[Link](s[j+1:j+1+length])
i = j+1+length
return res
**Logic:**
Explain prefix-based search.
class TrieNode:
def __init__(self):
[Link] = {}
[Link] = False
class Trie:
def __init__(self):
[Link] = TrieNode()