Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions Exercise_1.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
# Time Complexity:
# - Best Case: O(1) - When the target element is at the middle position of the array
# - Average Case: O(log n) - Each iteration divides the search space in half
# - Worst Case: O(log n) - When the target element is not in the array or at either extreme
#
# Space Complexity:
# - O(1) - Constant space complexity as we only use a fixed number of variables
# regardless of input size. No recursion stack or additional data structures needed.

# Python code to implement iterative Binary
# Search.

# It returns location of x in given array arr
# if present, else returns -1
def binarySearch(arr, l, r, x):

#write your code here
while l <= r :
mid = l + (r - l)//2

# Check if x is present at mid
if arr[mid] == x:
return mid

# If x is greater, ignore left half
elif arr[mid] < x:
l = mid + 1

# If x is smallerr, ignire left half
else:
r = mid - 1

# If we reach here, then the element was not present
return - 1



Expand All @@ -17,6 +41,6 @@ def binarySearch(arr, l, r, x):
result = binarySearch(arr, 0, len(arr)-1, x)

if result != -1:
print "Element is present at index % d" % result
print (f"Element is present at index = {result} ")
else:
print "Element is not present in array"
print ("Element is not present in array")
53 changes: 45 additions & 8 deletions Exercise_2.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,53 @@
# Python program for implementation of Quicksort Sort

# give you explanation for the approach

# Approach Explanation:
# QuickSort is a divide-and-conquer algorithm that works by:
# 1. Selecting a 'pivot' element from the array
# 2. Partitioning the array around the pivot (elements smaller than pivot go to the left, larger to the right)
# 3. Recursively applying the above steps to the sub-arrays

# Time Complexity:
# - Best Case: O(n log n) - When the pivot divides the array into roughly equal halves
# - Average Case: O(n log n) - Across all possible inputs
# - Worst Case: O(n²) - When the smallest or largest element is always chosen as pivot (e.g., already sorted array)
#
# Space Complexity:
# - O(log n) - For the recursion stack in the average case
# - O(n) - In the worst case when the recursion is unbalanced

def partition(arr,low,high):


#write your code here
# Choose the rightmost element as pivot
pivot = arr[high]

# Index of smaller element
i = low - 1

# Traverse through all elements
# compare each element with pivot
for j in range(low, high):
# If current element is smaller than or equal to pivot
if arr[j] <= pivot:
# Increment index of smaller element
i += 1
arr[i], arr[j] = arr[j], arr[i]

# Place pivot at its correct position
arr[i + 1], arr[high] = arr[high], arr[i + 1]

# Return the partition index
return i + 1


# Function to do Quick sort
def quickSort(arr,low,high):

#write your code here
def quickSort(arr,low,high):
if low < high:
# pi is partitioning index, arr[pi] is now at the right place
pi = partition(arr, low, high)

# Separately sort elements before and after partition
quickSort(arr, low, pi - 1)
quickSort(arr, pi + 1, high)


# Driver code to test above
arr = [10, 7, 8, 9, 1, 5]
Expand Down
29 changes: 28 additions & 1 deletion Exercise_3.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,45 @@ class Node:

# Function to initialise the node object
def __init__(self, data):
self.data = data
self.next = None

class LinkedList:

def __init__(self):
self.head = None


def push(self, new_data):
# Allocate the Node & put in the data
new_node = Node(new_data)

# Make next of new Node as head
new_node.next = self.head

# Move the head to point to new Node
self.head = new_node

# Function to get the middle of
# the linked list
# the linked list
# Time Complexity: O(n) - Only one traversal of the linked list is needed
# Space Complexity: O(1) - Only two pointer variables are used regardless of list size
def printMiddle(self):
# Initialize two pointers, one will go one step a time (slow)
# Another will go two steps a time (fast)
slow_ptr = self.head
fast_ptr = self.head

# Move fast_ptr by 2 and slow_ptr by 1
# Eventually, when fast_ptr reaches the end,
# slow_ptr will be at the middle
if self.head is not None:
while (fast_ptr is not None and fast_ptr.next is not None):
fast_ptr = fast_ptr.next.next
slow_ptr = slow_ptr.next

# slow_ptr is now at the middle
print("The middle element is: ", slow_ptr.data)

# Driver code
list1 = LinkedList()
Expand Down
52 changes: 48 additions & 4 deletions Exercise_4.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,56 @@
# Python program for implementation of MergeSort

# Time Complexity:
# - Best Case: O(n log n) - Even in the best case, we always divide the array and merge
# - Average Case: O(n log n) - Consistent performance regardless of input data
# - Worst Case: O(n log n) - Performance remains stable even with worst-case inputs

# Space Complexity:
# - O(n) - We need auxiliary space for storing temporary subarrays during merging

def mergeSort(arr):

#write your code here
if len(arr) > 1:
# Finding the mid of the array
mid = len(arr) // 2

# Dividing the array elements into 2 halves
L = arr[:mid]
R = arr[mid:]

# Sorting the first half
mergeSort(L)

# Sorting the second half
mergeSort(R)

i = j = k = 0

# Copy data to temp arrays L[] and R[]
while i < len(L) and j < len(R):
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1

# Checking if any element was left
while i < len(L):
arr[k] = L[i]
i += 1
k += 1

while j < len(R):
arr[k] = R[j]
j += 1
k += 1

# Code to print the list
def printList(arr):

#write your code here
for i in range(len(arr)):
print(arr[i], end=" ")
print()

# driver code to test the above code
if __name__ == '__main__':
Expand Down
80 changes: 78 additions & 2 deletions Exercise_5.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,86 @@
# Python program for implementation of Quicksort

# Time Complexity:
# - Best Case: O(n log n) - When partitions are balanced (pivot divides array equally)
# - Average Case: O(n log n) - Expected performance over all possible inputs
# - Worst Case: O(n^2) - When partition is unbalanced (already sorted arrays with last element as pivot)

# Space Complexity:
# - O(log n) - We need stack space for storing start and end indices
# - This is better than O(log n) recursive stack space in standard Quicksort implementation

# This function is same in both iterative and recursive
def partition(arr, l, h):
#write your code here
pivot = arr[h] # Choose the rightmost element as pivot
i = l - 1 # Index of smaller element

for j in range(l, h):
# If current element is smaller than or equal to pivot
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]

# Place pivot at its correct position
arr[i+1], arr[h] = arr[h], arr[i+1]
return i+1


def quickSortIterative(arr, l, h):
#write your code here
#Create an auxiliary stack
size = h - l + 1
stack = [0] * size

# Initialize top of stack
top = -1

# Push initial values of l and h to stack
top += 1
stack[top] = l
top += 1
stack[top] = h

# Keep popping from stack while it's not empty
while top >= 0:
# Pop h and l
h = stack[top]
top -= 1
l = stack[top]
top -= 1

# Set pivot element at its correct position
p = partition(arr, l, h)

# If there are elements on left side of pivot,
# then push left side to stack
if p - 1 > l:
top += 1
stack[top] = l
top += 1
stack[top] = p - 1

# If there are elements on right side of pivot,
# then push right side to stack
if p + 1 < h:
top += 1
stack[top] = p + 1
top += 1
stack[top] = h


# Driver code
if __name__ == "__main__":
arr = [10, 7, 8, 9, 1, 5]
n = len(arr)

print("Original array:")
for i in range(n):
print("%d" % arr[i], end=" ")
print()

# Call the quickSortIterative function
quickSortIterative(arr, 0, n-1)

print("Sorted array:")
for i in range(n):
print("%d" % arr[i], end=" ")
print()