From 30157cc06a96b72568d8da1981d6340039fdd51e Mon Sep 17 00:00:00 2001 From: Manasvi Reddy Date: Mon, 8 Jun 2026 19:49:03 -0400 Subject: [PATCH] Completed PreCourse-2 --- Exercise_1.py | 55 ++++++++++++++++++++++++--------------- Exercise_2.py | 62 +++++++++++++++++++++++++++----------------- Exercise_3.py | 30 ++++++++++++++++++++-- Exercise_4.py | 71 +++++++++++++++++++++++++++++++++++++++------------ Exercise_5.py | 56 +++++++++++++++++++++++++++++++++++++--- 5 files changed, 207 insertions(+), 67 deletions(-) diff --git a/Exercise_1.py b/Exercise_1.py index 3e6adcf4..8068cc9a 100644 --- a/Exercise_1.py +++ b/Exercise_1.py @@ -1,22 +1,35 @@ -# 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 - - - -# Test array -arr = [ 2, 3, 4, 10, 40 ] +# Time Complexity: O(log n): search window halves every iteration +# Space Complexity: O(1):only a fixed number of variables used +# Did this code successfully run on Leetcode: Yes +# Any problem you faced while coding this: No + +def binarySearch(arr, l, r, x): + low = l # start of search window, passed in as l + high = r # end of search window, passed in as r + + while low <= high: # keep searching while window is valid + mid = (low + high) // 2 # find middle index using integer division + + if arr[mid] == x: # found the target at mid + return mid # return the index + + elif arr[mid] < x: # target is larger, so it's in the right half + low = mid + 1 # shrink left boundary + + else: # target is smaller, so it's in the left half + high = mid - 1 # shrink right boundary + + return -1 # target not found in array + + +# Test array +arr = [2, 3, 4, 10, 40] x = 10 - -# Function call -result = binarySearch(arr, 0, len(arr)-1, x) - -if result != -1: - print "Element is present at index % d" % result -else: - print "Element is not present in array" + +# Function call +result = binarySearch(arr, 0, len(arr)-1, x) + +if result != -1: + print("Element is present at index", result) +else: + print("Element is not present in array") \ No newline at end of file diff --git a/Exercise_2.py b/Exercise_2.py index 35abf0dd..0e93d5ef 100644 --- a/Exercise_2.py +++ b/Exercise_2.py @@ -1,23 +1,39 @@ -# Python program for implementation of Quicksort Sort - -# give you explanation for the approach -def partition(arr,low,high): - - - #write your code here - - -# Function to do Quick sort -def quickSort(arr,low,high): - - #write your code here - -# Driver code to test above -arr = [10, 7, 8, 9, 1, 5] -n = len(arr) -quickSort(arr,0,n-1) -print ("Sorted array is:") -for i in range(n): - print ("%d" %arr[i]), - - +# Time Complexity : O(n log n) average, O(n^2) worst case (when array is already sorted) +# Space Complexity : O(log n) for recursion call stack +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding this : None + +# Python program for implementation of Quicksort Sort + +# Pick the last element as pivot. +# Use two pointers i and j to move all elements smaller than pivot to the left. +# Place pivot in its correct position. +# Recursively sort left and right halves. + +def partition(arr, low, high): + pivot = arr[high] # pick last element as pivot + i = low - 1 # i = wall, starts before the array (small zone is empty) + + for j in range(low, high): # j scans every element except pivot + if arr[j] <= pivot: # current element is smaller than pivot + i += 1 # push wall forward + arr[i], arr[j] = arr[j], arr[i] # swap small element into left zone + + arr[i+1], arr[high] = arr[high], arr[i+1] # place pivot right after small zone + return i + 1 # return pivot's correct index so quickSort can split + + +def quickSort(arr, low, high): + if low < high: # more than 1 element → keep sorting + pivot_index = partition(arr, low, high) # place pivot, get its index + quickSort(arr, low, pivot_index - 1) # sort left side of pivot + quickSort(arr, pivot_index + 1, high) # sort right side of pivot + + +# Driver code to test above +arr = [10, 7, 8, 9, 1, 5] +n = len(arr) +quickSort(arr, 0, n-1) +print("Sorted array is:") +for i in range(n): + print("%d" % arr[i]), diff --git a/Exercise_3.py b/Exercise_3.py index a26a69b8..979c2874 100644 --- a/Exercise_3.py +++ b/Exercise_3.py @@ -1,20 +1,46 @@ +# Time Complexity : O(n): we traverse the list once using fast pointer which covers n steps in n/2 iterations +# Space Complexity : O(1): only two extra pointers (slow and fast) are used, no extra storage +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding this : No +#We build a linked list by inserting each new node at the front and use two pointers slow and fast both starting at head. +#In every iteration, slow moves 1 step and fast moves 2 steps, so when fast can't move forward anymore, slow has covered exactly half the list. +#At that point slow.data gives us the middle element directly without any second traversal. +# Your code here along with comments explaining your approach + # Node class class Node: # Function to initialise the node object def __init__(self, data): - + self.data = data #where we are storing the entire data + self.next = None #right now the pointer to the next element is set to none class LinkedList: def __init__(self): + self.head = None #no elements have been added so we start at none + def push(self, new_data): + new_element = Node(new_data) # we are creating a new element + new_element.next = self.head #we point the new element to the head element + self.head = new_element #now the new element is the head element + + # adding in the front helps to keep the code simple # Function to get the middle of # the linked list def printMiddle(self): + slow = self.head #both slow and fast start at the head + fast = self.head + + #so by the time fast reaches the end, slow will reach the mid + while fast is not None and fast.next is not None: + slow = slow.next #slow jumps by one spot + fast = fast.next.next #fast jumps by two spots + print ("the Middle element is:",slow.data) + # Driver code list1 = LinkedList() @@ -23,4 +49,4 @@ def printMiddle(self): list1.push(2) list1.push(3) list1.push(1) -list1.printMiddle() +list1.printMiddle() \ No newline at end of file diff --git a/Exercise_4.py b/Exercise_4.py index 9bc25d3d..d14a859b 100644 --- a/Exercise_4.py +++ b/Exercise_4.py @@ -1,18 +1,55 @@ -# Python program for implementation of MergeSort +# Time Complexity : O(n log n):array is split log n times, each level takes O(n) to merge +# Space Complexity : O(n): extra space used for L and R arrays at each split +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding this : No + +# Your code here along with comments explaining your approach +# Approach: divide the array in half recursively until single elements,then merge two sorted halves back by always picking the smaller element first + +# Python program for implementation of MergeSort def mergeSort(arr): - - #write your code here - -# Code to print the list -def printList(arr): - - #write your code here - -# driver code to test the above code -if __name__ == '__main__': - arr = [12, 11, 13, 5, 6, 7] - print ("Given array is", end="\n") - printList(arr) - mergeSort(arr) - print("Sorted array is: ", end="\n") - printList(arr) + if len(arr) > 1: # base case: stop if single element + + mid = len(arr) // 2 # find the middle index + + L = arr[:mid] # left half + R = arr[mid:] # right half + + mergeSort(L) # recursively sort left half + mergeSort(R) # recursively sort right half + + i = j = k = 0 # i → left pointer, j → right pointer, k → arr pointer + + while i < len(L) and j < len(R): # compare elements from both halves + if L[i] <= R[j]: # left element is smaller or equal + arr[k] = L[i] # place left element into arr + i += 1 # move left pointer forward + else: # right element is smaller + arr[k] = R[j] # place right element into arr + j += 1 # move right pointer forward + k += 1 # move arr pointer forward + + while i < len(L): # copy remaining left elements if any + arr[k] = L[i] + i += 1 + k += 1 + + while j < len(R): # copy remaining right elements if any + arr[k] = R[j] + j += 1 + k += 1 + +# Code to print the list +def printList(arr): + for i in range(len(arr)): + print(arr[i], end=" ") # print each element separated by space + print() # move to next line after all elements + +# driver code to test the above code +if __name__ == '__main__': + arr = [12, 11, 13, 5, 6, 7] + print("Given array is", end="\n") + printList(arr) + mergeSort(arr) + print("Sorted array is: ", end="\n") + printList(arr) \ No newline at end of file diff --git a/Exercise_5.py b/Exercise_5.py index 1da24ffb..6d41e5a1 100644 --- a/Exercise_5.py +++ b/Exercise_5.py @@ -1,10 +1,58 @@ -# Python program for implementation of Quicksort +# Time Complexity : O(n log n) average, O(n^2) worst case: depends on pivot choice +# Space Complexity : O(n), explicit stack used to store subarray boundaries +# Did this code successfully run on Leetcode : Yes +# Any problem you faced while coding this : No + +# Your code here along with comments explaining your approach +# Approach: pick last element as pivot, place it in correct position via partition, +# then use an explicit stack to iteratively sort left and right subarrays -# This function is same in both iterative and recursive def partition(arr, l, h): - #write your code here + pivot = arr[h] # last element is the pivot + i = l - 1 # boundary of smaller elements + + for j in range(l, h): # scan every element except pivot + if arr[j] <= pivot: # if element belongs on left side + i += 1 # expand left boundary + arr[i], arr[j] = arr[j], arr[i] # swap into left side + arr[i+1], arr[h] = arr[h], arr[i+1] # place pivot in correct spot + return i + 1 # return pivot's final index def quickSortIterative(arr, l, h): - #write your code here + stack = [0] * (h - l + 1) # stack to store subarray boundaries + top = -1 # top = -1 means stack is empty + + top += 1 + stack[top] = l # push starting left index + top += 1 + stack[top] = h # push starting right index + + while top >= 0: # loop until stack is empty + h = stack[top] # pop right boundary + top -= 1 + l = stack[top] # pop left boundary + top -= 1 + + p = partition(arr, l, h) # partition array, p is pivot's final index + + if p - 1 > l: # left subarray has more than 1 element + top += 1 + stack[top] = l # push left boundary + top += 1 + stack[top] = p - 1 # push right boundary of left subarray + + if p + 1 < h: # right subarray has more than 1 element + top += 1 + stack[top] = p + 1 # push left boundary of right subarray + top += 1 + stack[top] = h # push right boundary +# Driver code +arr = [10, 80, 30, 90, 40, 50, 70] +n = len(arr) +print("Given array is") +print(arr) +quickSortIterative(arr, 0, n - 1) +print("Sorted array is") +print(arr)