From 20bbc75f065e6c7ece53a787982933df53b57430 Mon Sep 17 00:00:00 2001 From: Prajwal Date: Thu, 24 Oct 2024 23:21:22 -0700 Subject: [PATCH] Added the binary search exercises --- 2dmatrix.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ rotated.py | 40 +++++++++++++++++++++++++++++++++++++++ unknown_size.py | 29 ++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 2dmatrix.py create mode 100644 rotated.py create mode 100644 unknown_size.py diff --git a/2dmatrix.py b/2dmatrix.py new file mode 100644 index 00000000..1d617078 --- /dev/null +++ b/2dmatrix.py @@ -0,0 +1,50 @@ +# The code defines a searchMatrix method to locate a target value within a 2D matrix. +# The matrix has sorted properties: each row is sorted from left to right, and the last element of each row is less than or equal to the first element of the next row. +# +# The search is conducted in two phases: +# 1. Locate the correct row where the target might be present: +# - Two pointers, 'top' and 'bot', represent the range of rows to consider. +# - A binary search is performed over the rows: +# - If the target is greater than the last element of the current row (matrix[row][-1]), the search moves down by setting top = row + 1. +# - If the target is less than the first element of the current row (matrix[row][0]), the search moves up by setting bot = row - 1. +# - If the target is within the current row range, we break out to proceed with a search within this row. +# - If no such row is found, the method returns False, as the target is not in the matrix. +# +# 2. Perform binary search within the identified row: +# - Two pointers, 'l' and 'r', define the search range within the row. +# - If matrix[row][m] (mid-point element) equals the target, True is returned. +# - If matrix[row][m] is less than the target, l is updated to m + 1 to search the right half of the row. +# - If matrix[row][m] is greater than the target, r is updated to m - 1 to search the left half of the row. +# If the target is not found after both searches, the method returns False. +# +# TC: O(log m + log n) - Binary search over rows (log m) and columns (log n). +# SC: O(1) - Constant space is used, as only pointers are maintained for each binary search step. + + +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + ROWS, COLS = len(matrix), len(matrix[0]) + + top, bot = 0, ROWS - 1 + while top <= bot: + row = (top + bot) // 2 + if target > matrix[row][-1]: + top = row + 1 + elif target < matrix[row][0]: + bot = row - 1 + else: + break + + if not (top <= bot): + return False + row = (top + bot) // 2 + l, r = 0, COLS - 1 + while l <= r: + m = (l + r) // 2 + if target > matrix[row][m]: + l = m + 1 + elif target < matrix[row][m]: + r = m - 1 + else: + return True + return False diff --git a/rotated.py b/rotated.py new file mode 100644 index 00000000..71d8cac9 --- /dev/null +++ b/rotated.py @@ -0,0 +1,40 @@ +# The code defines a search method to find a target value in a rotated sorted array using binary search. +# The array is sorted but rotated, meaning it was initially sorted and then rotated at some pivot unknown to us. +# Two pointers, 'l' and 'r', are used to represent the left and right boundaries of the current search space. +# +# In each iteration: +# - The mid-point (mid) is calculated to divide the array in half. +# - If nums[mid] equals the target, mid is returned as the index where the target is found. +# - If the left half (from nums[l] to nums[mid]) is sorted: +# - If the target lies within this sorted half (target >= nums[l] and target < nums[mid]), we narrow the search to this half by setting r = mid - 1. +# - Otherwise, we search the right half by setting l = mid + 1. +# - If the right half (from nums[mid] to nums[r]) is sorted: +# - If the target lies within this sorted half (target > nums[mid] and target <= nums[r]), we search this half by setting l = mid + 1. +# - Otherwise, we narrow the search to the left half by setting r = mid - 1. +# If the target is not found after the loop, -1 is returned, indicating it is not present in the array. +# +# TC: O(log n) - Binary search halves the search space each iteration. +# SC: O(1) - Constant space usage, as only pointers for the search range and mid-point are maintained. + + +class Solution: + def search(self, nums: List[int], target: int) -> int: + l, r = 0, len(nums) - 1 + + while l <= r: + mid = (l + r) // 2 + if target == nums[mid]: + return mid + + if nums[l] <= nums[mid]: + if target > nums[mid] or target < nums[l]: + l = mid + 1 + else: + r = mid - 1 + + else: + if target < nums[mid] or target > nums[r]: + r = mid - 1 + else: + l = mid + 1 + return -1 diff --git a/unknown_size.py b/unknown_size.py new file mode 100644 index 00000000..ab302302 --- /dev/null +++ b/unknown_size.py @@ -0,0 +1,29 @@ +# The code implements a search algorithm for an unknown-sized, sorted array using an external interface 'ArrayReader'. +# The search method utilizes binary search to efficiently locate the target value within the array. +# An initial left (l) and right (r) boundary is set, where: +# - 'l' starts at index 0. +# - 'r' is obtained through reader.get(-1), which is assumed to return the size or a boundary of the array. +# In each iteration, the mid-point (mid) is calculated to split the search space: +# - If reader.get(mid) equals the target, mid is returned as the index where the target is found. +# - If reader.get(mid) is greater than the target, the search shifts to the left half by setting r = mid - 1. +# - Otherwise, it shifts to the right half by setting l = mid + 1. +# If the target is not found after the loop, -1 is returned, indicating the target does not exist in the array. +# +# TC: O(log n) - Since binary search reduces the search space by half each iteration. +# SC: O(1) - Constant space is used, as only pointers for the search range and mid-point are maintained. + + +class Solution: + def search(self, reader: 'ArrayReader', target: int) -> int: # type: ignore + l, r = 0, reader.get(-1) + print(r) + while l <= r: + mid = (l + r) // 2 + if reader.get(mid) == target: + return mid + elif reader.get(mid) > target: + r = mid - 1 + else: + l = mid + 1 + return -1 + \ No newline at end of file