DSA Interview Practice Sheet
DSA Interview Practice Sheet
Example:
Steps:
o Initialize:
max_sum = nums[0], current_sum = 0
o Loop through array:
§ Add current element → current_sum += nums[i]
§ Update max_sum = max(max_sum, current_sum)
§ If current_sum < 0, reset current_sum = 0
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Time Complexity: O(n)
Space Complexity: O(1)
Python Code
def max_subarray(nums):
max_sum = nums[0] # store the maximum sum found
current_sum = 0 # store the current running sum
return max_sum
# Example run
arr = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print("Maximum Subarray Sum:", max_subarray(arr))
Example:
Steps:
Python Code
def rotate_array(nums, k):
n = len(nums)
k = k % n # handle if k > n
return nums[-k:] + nums[:-k]
# Example run
arr = [1,2,3,4,5,6,7]
k = 3
print("Rotated Array:", rotate_array(arr, k))
Example:
Example:
nums = [3, 0, 1]
n = 3
expected_sum = 3*4/2 = 6
actual_sum = 3+0+1 = 4
missing = 6-4 = 2
Python Code
def find_missing_number(nums):
n = len(nums)
expected_sum = n * (n + 1) // 2
actual_sum = sum(nums)
return expected_sum - actual_sum
# Example run
arr = [3, 0, 1]
print("Missing Number:", find_missing_number(arr))
Example:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Logic & Explanation
1. Brute Force Approach
o Compare each element with every other.
o Time Complexity: O(n^2).
2. Sorting Approach
o Sort the array.
o Duplicate will appear consecutively.
o Time Complexity: O(n log n).
3. Hashing / Set Approach
o Keep a set.
o While iterating, if element already exists → that’s duplicate.
o Time Complexity: O(n), Space: O(n).
4. Optimal Approach (Floyd’s Cycle Detection Algorithm – Tortoise & Hare)
o Treat the array like a linked list where nums[i] points to nums[nums[i]].
o Since there’s a duplicate, there will be a cycle.
o Use slow & fast pointers to detect the cycle → entry point of cycle =
duplicate.
o Time Complexity: O(n), Space: O(1) → Best method (often asked in
Amazon, Microsoft).
# Example run
arr = [1, 3, 4, 2, 2]
print("Duplicate Element:", find_duplicate(arr))
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
# Phase 2: Find entrance to cycle
slow = nums[0]
while slow != fast:
slow = nums[slow]
fast = nums[fast]
return slow
# Example run
arr = [1, 3, 4, 2, 2]
print("Duplicate Element (Optimal):", find_duplicate(arr))
Example 1:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Python Code (Two Pointers Method)
def merge_sorted_arrays(arr1, arr2):
i, j = 0, 0
merged = []
return merged
# Example run
arr1 = [1,3,5]
arr2 = [2,4,6]
print("Merged Array:", merge_sorted_arrays(arr1, arr2))
Example:
# Example run
arr = [2,0,2,1,1,0]
print("Sorted Array:", sort_colors(arr))
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Given an array of integers nums and an integer target, return indices of the two numbers
such that they add up to target.
You may assume that each input has exactly one solution, and you may not use the same
element twice.
Example:
# Example run
arr = [2, 7, 11, 15]
target = 9
print("Indices:", two_sum(arr, target))
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Problem 8: Maximum Product Subarray
Problem Statement
Given an integer array nums, find the contiguous subarray (containing at least one number)
which has the largest product, and return the product.
Example:
Example:
nums = [2,3,-2,4]
max product is 6 (from [2,3])
2. Key Idea
o At each step, we need to keep track of:
§ max_product (maximum till now)
§ min_product (minimum till now, because multiplying with negative
may give new max)
o Formula:
o temp = max_product
o max_product = max(num, num*max_product, num*min_product)
o min_product = min(num, num*temp, num*min_product)
o Update result = max(result, max_product)
3. Time Complexity: O(n)
Space Complexity: O(1)
Python Code
def max_product_subarray(nums):
max_product = nums[0]
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
min_product = nums[0]
result = nums[0]
return result
# Example run
arr = [2,3,-2,4]
print("Maximum Product Subarray:", max_product_subarray(arr))
Example:
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with length 3.
Example Walkthrough:
s = "abcabcbb"
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
• Expand → "ab", max=2
• Expand → "abc", max=3
• Duplicate "a" → shrink left → "bca" still valid
• Continue → "abc", "cab", max stays 3
Python Code
def length_of_longest_substring(s):
char_index = {} # stores last index of each character
left = 0
max_length = 0
return max_length
# Example run
s = "abcabcbb"
print("Length of Longest Substring:", length_of_longest_substring(s))
Example:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Input: s1 = "listen", s2 = "silent"
Output: True
Explanation: Both have the same letters, just in different order.
• Time: O(n)
• Space: O(1) (since alphabet size is fixed)
Python Code
Approach 1: Sorting
def are_anagrams_sorting(s1, s2):
return sorted(s1) == sorted(s2)
# Example run
print(are_anagrams_sorting("listen", "silent")) # True
print(are_anagrams_sorting("hello", "world")) # False
# Example run
print(are_anagrams_count("listen", "silent")) # True
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
print(are_anagrams_count("race", "care")) # True
print(are_anagrams_count("rat", "car")) # False
Example:
Python Code
def reverse_words(s):
# Split string into words and remove extra spaces
words = [Link]()
# Reverse the list of words
reversed_words = words[::-1]
# Join words with a single space
return ' '.join(reversed_words)
# Example run
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
s = " hello world "
print("Reversed Words:", reverse_words(s))
Example:
For interviews, often the naive solution is enough unless asked for optimization.
Python Code
Approach 1: Naive
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
def str_str(haystack, needle):
if not needle:
return 0 # empty needle
n, m = len(haystack), len(needle)
for i in range(n - m + 1):
if haystack[i:i + m] == needle:
return i
return -1
# Example run
haystack = "hello"
needle = "ll"
print("First Occurrence Index:", str_str(haystack, needle))
Logic:
Python Code:
def factorial(n):
if n == 0 or n == 1:
return 1
return n * factorial(n-1)
# Example
print("5! =", factorial(5))
Output:
5! = 120
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Problem 14: Fibonacci Using Recursion
Problem Statement:
Print the nth Fibonacci number: 0, 1, 1, 2, 3, 5, ...
Logic:
Python Code:
def fibonacci(n):
if n == 0:
return 0
if n == 1:
return 1
return fibonacci(n-1) + fibonacci(n-2)
# Example
print("Fibonacci(6) =", fibonacci(6))
Output:
Fibonacci(6) = 8
Logic:
Python Code:
# Example
permute(list("ABC"))
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Output:
ABC
ACB
BAC
BCA
CBA
CAB
Logic:
Python Code:
# Example
tower_of_hanoi(3, 'A', 'B', 'C')
Output:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Problem Statement:
Generate all subsets of [1,2,3].
Logic:
Python Code:
# Example
subsets([1,2,3])
Output:
[1, 2, 3]
[1, 2]
[1, 3]
[1]
[2, 3]
[2]
[3]
[]
Logic:
def solve_nqueens(n):
board = [-1]*n # board[i] = column of queen in row i
def is_safe(row, col):
for r in range(row):
c = board[r]
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
if c == col or abs(r - row) == abs(c - col):
return False
return True
def place_queen(row):
if row == n:
print(board)
return
for col in range(n):
if is_safe(row, col):
board[row] = col
place_queen(row+1)
board[row] = -1 # backtrack
place_queen(0)
# Example
solve_nqueens(4)
[1, 3, 0, 2]
[2, 0, 3, 1]
Logic:
Python Code:
def rat_in_maze(maze):
n = len(maze)
path = []
visited = [[False]*n for _ in range(n)]
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
[Link]()
visited[nx][ny] = False
visited[0][0] = True
[Link]((0,0))
backtrack(0,0)
# Example
maze = [[1,0,0],
[1,1,0],
[0,1,1]]
rat_in_maze(maze)
[(0, 0), (1, 0), (1, 1), (2, 1), (2, 2)]
Logic:
• Use DFS for each cell that matches the first character.
• Track visited cells.
• Recurse for next character in 4 directions.
Python Code:
# Example
board = [["A","B","C","E"],
["S","F","C","S"],
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
["A","D","E","E"]]
word = "ABCCED"
print("Word Found:", exist(board, word))
Output:
Logic:
Python Code:
# Example
arr = [1,3,5,7,9]
print("Index of 5:", binary_search(arr, 5))
Output:
Index of 5: 2
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Problem 22: First and Last Occurrence (in Sorted Array)
Problem Statement:
Find first and last positions of target in a sorted array.
Logic:
• Use binary search twice: once for first occurrence, once for last occurrence.
Python Code:
def binary_search_right():
left, right = 0, len(nums)-1
idx = -1
while left <= right:
mid = (left+right)//2
if nums[mid] == target:
idx = mid
left = mid + 1
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return idx
# Example
arr = [1,2,2,2,3,4]
print("First & Last Occurrence of 2:", first_last_occurrence(arr,2))
Output:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Problem Statement:
Already covered in Arrays section – Two Pointers Method can be reused.
Logic:
Python Code:
def find_peak(nums):
left, right = 0, len(nums)-1
while left < right:
mid = (left + right)//2
if nums[mid] < nums[mid+1]:
left = mid + 1
else:
right = mid
return left
# Example
arr = [1,3,4,2,1]
print("Peak Element Index:", find_peak(arr))
Output:
Logic:
Python Code:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
def search_rotated(nums, target):
left, right = 0, len(nums)-1
while left <= right:
mid = (left+right)//2
if nums[mid] == target:
return mid
if nums[left] <= nums[mid]:
if nums[left] <= target < nums[mid]:
right = mid -1
else:
left = mid + 1
else:
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
return -1
# Example
arr = [4,5,6,7,0,1,2]
print("Index of 0:", search_rotated(arr,0))
Output:
Index of 0: 4
Logic:
Python Code:
def count_inversions(arr):
def merge_sort(nums):
if len(nums) <=1:
return nums,0
mid = len(nums)//2
left,inv_left = merge_sort(nums[:mid])
right,inv_right = merge_sort(nums[mid:])
merged, inv_count = [], inv_left + inv_right
i=j=0
while i<len(left) and j<len(right):
if left[i] <= right[j]:
[Link](left[i])
i+=1
else:
[Link](right[j])
inv_count += len(left)-i
j+=1
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
merged += left[i:] + right[j:]
return merged, inv_count
_, count = merge_sort(arr)
return count
# Example
arr = [2,4,1,3,5]
print("Inversions Count:", count_inversions(arr))
Output:
Inversions Count: 3
Logic:
import heapq
# Example
arr = [3,2,1,5,6,4]
print("2nd Largest:", kth_largest(arr,2))
Output:
2nd Largest: 5
Python Code:
def quicksort(arr):
if len(arr)<=1:
return arr
pivot = arr[len(arr)//2]
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
left = [x for x in arr if x<pivot]
middle = [x for x in arr if x==pivot]
right = [x for x in arr if x>pivot]
return quicksort(left)+middle+quicksort(right)
# Example
arr = [3,6,8,10,1,2,1]
print("Sorted Array:", quicksort(arr))
Output:
Logic:
Python Code:
# Example
matrix = [[1,4,7,11],
[2,5,8,12],
[3,6,9,16]]
print("Target 5 Found:", search_matrix(matrix,5))
Output:
Logic:
Python Code:
class Node:
def __init__(self, data):
[Link] = data
[Link] = None
def reverse_linked_list(head):
prev = None
curr = head
while curr:
next_node = [Link]
[Link] = prev
prev = curr
curr = next_node
return prev
# Example
head = Node(1)
[Link] = Node(2)
[Link] = Node(3)
rev_head = reverse_linked_list(head)
curr = rev_head
while curr:
print([Link], end=" ")
curr = [Link]
Output:
3 2 1
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Logic:
Python Code:
def has_cycle(head):
slow = fast = head
while fast and [Link]:
slow = [Link]
fast = [Link]
if slow == fast:
return True
return False
# Example
head = Node(1)
[Link] = Node(2)
[Link] = Node(3)
[Link] = head # cycle
print("Cycle Detected:", has_cycle(head))
Output:
Logic:
Python Code:
def find_middle(head):
slow = fast = head
while fast and [Link]:
slow = [Link]
fast = [Link]
return [Link]
# Example
head = Node(1)
[Link] = Node(2)
[Link] = Node(3)
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
[Link] = Node(4)
print("Middle Node:", find_middle(head))
Output:
Middle Node: 2
Logic:
Python Code:
# Example
l1 = Node(1); [Link] = Node(3); [Link] = Node(5)
l2 = Node(2); [Link] = Node(4); [Link] = Node(6)
merged = merge_sorted_lists(l1,l2)
curr = merged
while curr:
print([Link], end=" ")
curr = [Link]
Output:
1 2 3 4 5 6
# Example
s = StackArray()
[Link](1); [Link](2); [Link](3)
print("Top:", [Link]())
print("Pop:", [Link]())
Output:
Top: 3
Pop: 3
class StackNode:
def __init__(self, data):
[Link] = data
[Link] = None
class StackLinkedList:
def __init__(self):
[Link] = None
def push(self, val):
node = StackNode(val)
[Link] = [Link]
[Link] = node
def pop(self):
if [Link]:
val = [Link]
[Link] = [Link]
return val
def peek(self):
return [Link] if [Link] else None
# Example
s = StackLinkedList()
[Link](1); [Link](2)
print("Top:", [Link]())
print("Pop:", [Link]())
Output:
Top: 2
Pop: 2
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Problem 35: Implement Queue using Array & Linked
List
Logic (Array):
class QueueArray:
def __init__(self):
self.q = []
def enqueue(self, val):
[Link](val)
def dequeue(self):
return [Link](0) if self.q else None
def front(self):
return self.q[0] if self.q else None
# Example
q = QueueArray()
[Link](1); [Link](2)
print("Front:", [Link]())
print("Dequeue:", [Link]())
Output:
Front: 1
Dequeue: 1
class QueueNode:
def __init__(self, data):
[Link] = data
[Link] = None
class QueueLinkedList:
def __init__(self):
[Link] = [Link] = None
def enqueue(self, val):
node = QueueNode(val)
if not [Link]:
[Link] = [Link] = node
return
[Link] = node
[Link] = node
def dequeue(self):
if [Link]:
val = [Link]
[Link] = [Link]
if not [Link]:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
[Link] = None
return val
def peek(self):
return [Link] if [Link] else None
# Example
q = QueueLinkedList()
[Link](1); [Link](2)
print("Front:", [Link]())
print("Dequeue:", [Link]())
Output:
Front: 1
Dequeue: 1
• Use one array with two pointers: top1 from start, top2 from end.
• Push/Pop accordingly, stop when top1+1 == top2.
class TwoStacks:
def __init__(self, n):
[Link] = n
[Link] = [None]*n
self.top1 = -1
self.top2 = n
def push1(self, val):
if self.top1+1 == self.top2:
print("Overflow")
return
self.top1 += 1
[Link][self.top1] = val
def push2(self, val):
if self.top1+1 == self.top2:
print("Overflow")
return
self.top2 -= 1
[Link][self.top2] = val
def pop1(self):
if self.top1==-1: return None
val = [Link][self.top1]
self.top1 -=1
return val
def pop2(self):
if self.top2==[Link]: return None
val = [Link][self.top2]
self.top2 +=1
return val
# Example
s = TwoStacks(5)
s.push1(1); s.push2(5)
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
print("Pop1:", s.pop1())
print("Pop2:", s.pop2())
Output:
Pop1: 1
Pop2: 5
Logic:
def next_greater(nums):
res = [-1]*len(nums)
stack = []
for i in range(len(nums)-1,-1,-1):
while stack and stack[-1]<=nums[i]:
[Link]()
res[i] = stack[-1] if stack else -1
[Link](nums[i])
return res
# Example
arr = [4,5,2,25]
print("Next Greater:", next_greater(arr))
Output:
Logic:
def is_balanced(s):
stack = []
mapping = {')':'(', '}':'{', ']':'['}
for char in s:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
if char in "({[":
[Link](char)
elif char in ")}]":
if not stack or stack[-1]!=mapping[char]:
return False
[Link]()
return not stack
# Example
s = "{[()]}"
print("Balanced:", is_balanced(s))
Output:
Balanced: True
class CircularQueue:
def __init__(self, k):
self.q = [None]*k
[Link] = [Link] = -1
[Link] = k
def dequeue(self):
if [Link] == -1:
print("Underflow - Queue is Empty")
return None
val = self.q[[Link]]
if [Link] == [Link]: # only one element left
[Link] = [Link] = -1
else:
[Link] = ([Link]+1) % [Link]
return val
def front(self):
return self.q[[Link]] if [Link] != -1 else None
def display(self):
if [Link] == -1:
print("Queue is Empty")
return
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
i = [Link]
elements = []
while True:
[Link](self.q[i])
if i == [Link]:
break
i = (i+1) % [Link]
print("Queue:", elements)
# Example
cq = CircularQueue(3)
[Link](1)
[Link](2)
[Link](3) # Queue is full now
[Link]()
Logic:
Pseudocode (recursive):
preorder(node):
if node is None: return
visit(node)
preorder([Link])
preorder([Link])
inorder(node):
if node is None: return
inorder([Link])
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
visit(node)
inorder([Link])
postorder(node):
if node is None: return
postorder([Link])
postorder([Link])
visit(node)
# Recursive traversals
def preorder_recursive(root, res):
if not root: return
[Link]([Link])
preorder_recursive([Link], res)
preorder_recursive([Link], res)
def inorder_iterative(root):
res, stack = [], []
curr = root
while curr or stack:
while curr:
[Link](curr)
curr = [Link]
curr = [Link]()
[Link]([Link])
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
curr = [Link]
return res
def postorder_iterative(root):
# Two-stack method
if not root: return []
s1, s2 = [root], []
while s1:
node = [Link]()
[Link]([Link])
if [Link]: [Link]([Link])
if [Link]: [Link]([Link])
return s2[::-1]
# Example usage:
# root = TreeNode(1); [Link] = TreeNode(2); [Link] = TreeNode(3)
# r = []; preorder_recursive(root, r); print(r)
Pseudocode:
Python code:
def level_order(root):
if not root: return []
q = deque([root])
result = []
while q:
level_size = len(q)
level = []
for _ in range(level_size):
node = [Link]()
[Link]([Link])
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
if [Link]: [Link]([Link])
if [Link]: [Link]([Link])
[Link](level)
return result
def level_order_flat(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
Pseudocode:
height(node):
if node is None: return 0
return 1 + max(height([Link]), height([Link]))
Python code:
def height(root):
if not root: return 0
return 1 + max(height([Link]), height([Link]))
Logic: Naive approach computes heights repeatedly (O(n^2)). Optimal approach: postorder
traversal that returns height, or -1 sentinel if subtree is unbalanced. This yields O(n) time.
Pseudocode (optimal):
check(node):
if node is None: return 0
left_h = check([Link]); if left_h == -1: return -1
right_h = check([Link]); if right_h == -1: return -1
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
if abs(left_h - right_h) > 1: return -1
return 1 + max(left_h, right_h)
Python code:
def is_balanced(root):
def helper(node):
if not node: return 0
lh = helper([Link])
if lh == -1: return -1
rh = helper([Link])
if rh == -1: return -1
if abs(lh - rh) > 1:
return -1
return 1 + max(lh, rh)
return helper(root) != -1
Logic: Postorder recursion: if current node is p or q, return it. Otherwise, get left =
recurse(left), right = recurse(right).
Pseudocode:
LCA(node, p, q):
if node is None: return None
if node is p or node is q: return node
left = LCA([Link], p, q)
right = LCA([Link], p, q)
if left and right: return node
return left if left else right
Notes: If you have references to node objects instead of values, compare nodes directly (if
root is p or root is q).
Logic: Use recursion with allowable (min_val, max_val) range that every node must fall
into. Initial range is (-inf, +inf).
Pseudocode:
Python code:
import math
def is_bst(root):
def helper(node, low, high):
if not node: return True
if not (low < [Link] < high): return False
return helper([Link], low, [Link]) and helper([Link],
[Link], high)
return helper(root, -[Link], [Link])
Alternative: Inorder traversal must produce strictly increasing sequence; you can check that
iteratively.
Logic: For each node, longest path through it = left_height + right_height + 1 (if
counting nodes). We can compute heights bottom-up and keep a global maximum diameter.
O(n) time.
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
Pseudocode:
max_diameter = 0
height(node):
if node is None: return 0
lh = height([Link])
rh = height([Link])
max_diameter = max(max_diameter, lh + rh + 1)
return 1 + max(lh, rh)
Python code:
def diameter_of_binary_tree(root):
# returns diameter in nodes; to get edges subtract 1
max_dia = 0
def height(node):
nonlocal max_dia
if not node: return 0
lh = height([Link])
rh = height([Link])
# path through node (count nodes)
max_dia = max(max_dia, lh + rh + 1)
return 1 + max(lh, rh)
height(root)
return max_dia # nodes; for edges return max_dia - 1 if desired
Logic: Simple recursion: if node is leaf (not [Link] and not [Link]) count 1;
else sum counts in subtrees.
Pseudocode:
count_leaves(node):
if node is None: return 0
if [Link] is None and [Link] is None: return 1
return count_leaves([Link]) + count_leaves([Link])
Python code:
def count_leaf_nodes(root):
if not root: return 0
if not [Link] and not [Link]:
return 1
return count_leaf_nodes([Link]) + count_leaf_nodes([Link])
Logic:
Pseudocode (BFS):
BFS(graph):
visited = set()
for each vertex v:
if v not visited:
queue = [v]; [Link](v)
while queue:
node = [Link](0)
visit(node)
for nbr in graph[node]:
if nbr not visited:
[Link](nbr); [Link](nbr)
def bfs_graph(adj):
# adj: dict {node: [neighbors]}
visited = set()
order = []
for start in adj:
if start in visited: continue
q = deque([start])
[Link](start)
while q:
node = [Link]()
[Link](node)
for nbr in [Link](node, []):
if nbr not in visited:
[Link](nbr)
[Link](nbr)
return order
def dfs_graph_recursive(adj):
visited = set()
order = []
def dfs(u):
[Link](u)
[Link](u)
for v in [Link](u, []):
if v not in visited:
dfs(v)
for node in adj:
if node not in visited:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
dfs(node)
return order
Logic: Use DFS with parent tracking (since undirected edges lead back to parent). While
visiting neighbors:
Pseudocode (DFS):
visited = set()
for each vertex v:
if v not visited:
if dfs(v, parent=-1): return True
return False
dfs(u, parent):
[Link](u)
for v in adj[u]:
if v not in visited:
if dfs(v, u): return True
elif v != parent:
return True
return False
def has_cycle_undirected(adj):
visited = set()
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
def dfs(u, parent):
[Link](u)
for v in [Link](u, []):
if v not in visited:
if dfs(v, u):
return True
elif v != parent:
return True
return False
# initialize
for node in adj:
parent[node] = node
for u in adj:
for v in adj[u]:
if u < v: # ensure each undirected edge seen once (if nodes
comparable)
if not union(u, v):
return True
return False
Examples
# Build a sample tree:
# 1
# / \
# 2 3
# / \
# 4 5
root = TreeNode(1)
[Link] = TreeNode(2); [Link] = TreeNode(3)
[Link] = TreeNode(4); [Link] = TreeNode(5)
# Traversals:
print("Preorder recursive:", end=" "); r=[]; preorder_recursive(root, r);
print(r)
print("Inorder iterative:", inorder_iterative(root))
print("Level order:", level_order(root))
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
print("Height:", height(root))
print("Is balanced:", is_balanced(root))
print("LCA of 4 and 5:", lowest_common_ancestor(root, 4, 5).val)
print("Is BST:", is_bst(root))
print("Diameter (nodes):", diameter_of_binary_tree(root))
print("Leaf count:", count_leaf_nodes(root))
# Graph example:
adj = {1:[2,3], 2:[1,4], 3:[1], 4:[2]}
print("BFS order:", bfs_graph(adj))
print("DFS recursive:", dfs_graph_recursive(adj))
print("Has cycle:", has_cycle_undirected(adj))
Logic:
Python Code:
# Memoization
def fib_memo(n, memo={}):
if n in memo: return memo[n]
if n <= 1: return n
memo[n] = fib_memo(n-1, memo) + fib_memo(n-2, memo)
return memo[n]
# Tabulation
def fib_tab(n):
if n <= 1: return n
dp = [0]*(n+1)
dp[0], dp[1] = 0, 1
for i in range(2, n+1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
# Space optimized
def fib_opt(n):
if n <= 1: return n
a, b = 0, 1
for _ in range(2, n+1):
a, b = b, a+b
return b
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
51. Longest Common Subsequence (LCS)
Problem Statement: Given two strings, find the length of the longest subsequence present in
both.
Logic:
Python Code:
# Example
# print(lcs("abcde", "ace")) # Output: 3
Logic:
• DP solution: dp[i] = 1 + max(dp[j]) for all j < i and arr[j] < arr[i].
O(n^2).
• Optimized solution: Use binary search with a sub list. O(n log n).
Python Code:
def lis_dp(nums):
n = len(nums)
dp = [1]*n
for i in range(n):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j]+1)
return max(dp)
# Optimized (n log n)
import bisect
def lis_binary(nums):
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
sub = []
for x in nums:
i = bisect.bisect_left(sub, x)
if i == len(sub):
[Link](x)
else:
sub[i] = x
return len(sub)
Logic:
Python Code:
Logic:
• Recursive relation:
dp[i][w] = max(val[i-1] + dp[i-1][w-wt[i-1]], dp[i-1][w]) if wt[i-1]
<= w
• Else: dp[i-1][w].
Python Code:
Logic:
Python Code:
def min_cost_path(grid):
m, n = len(grid), len(grid[0])
dp = [[0]*n for _ in range(m)]
dp[0][0] = grid[0][0]
for i in range(1, m):
dp[i][0] = dp[i-1][0] + grid[i][0]
for j in range(1, n):
dp[0][j] = dp[0][j-1] + grid[0][j]
for i in range(1, m):
for j in range(1, n):
dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])
return dp[m-1][n-1]
Logic:
Python Code:
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer
for j in range(n+1):
dp[0][j] = j # insertions
for i in range(1, m+1):
for j in range(1, n+1):
if s1[i-1] == s2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = 1 + min(dp[i-1][j], # delete
dp[i][j-1], # insert
dp[i-1][j-1]) # replace
return dp[m][n]
────────────────────────────────────────────────────────────
Created by Nishant Thakur | 9354057409
Technical Trainer