XXXXXXXX

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 7

Islamic University of Technology

Department of Computer Science and Engineering


BSc., Computer Science and Engineering

Algorithm Engineering Lab Report

Lab 0

Written By
Syed Fateen Navid Haider, 190041226

Submitted to:
Md. Atiqur Rahman
Lecturer,Department of CSE

January 2024
Solution to Task 1

We have been given the following set of equations.

1. f1 (n) = n0.999 log2 (n)


2. f2 (n) = 107 ∗ n
3. f3 (n) = (1000001 ∗ 10−6 )n

4. f4 (n) = n!
7
5. f5 (n) = 210∗10

6. f6 (n) = n ∗ n

7. f7 (n) = n n
Pn
8. f8 (n) = i=1 (i + 1)

Analyzing each function we get,

1. f1 (n) = n0.999 log2 (n) – This is a polynomial function with a logarithmic term, therefore it
grows more slowly than pure polynomials.
2. f2 (n) = 107 ∗ n – This is a one-degree polynomial linear function.

3. f3 (n) = (1000001 ∗ 10−6 )n – This function is exponential, with a base raised to the power of
n.
4. f4 (n) = n! – This is a factorial function, and it rises rapidly.
7
5. f5 (n) = 210∗10 – This is an exponential function with a high exponent.

6. f6 (n) = n ∗ n – This is a polynomial function with a square root component.

7. f7 (n) = n n – This is an exponential function with a fractional exponent.
Pn
8. f8 (n) = i=1 (i + 1) – This is a product of terms, which is likely to increase faster than
polynomial functions.
Calculating the Big-O complexity of each function, we get

1. f1 (n) = n0.999 log2 (n) – O(n0.999 · logn)


f2 (n) = 107 ∗ n – O(n)

2. f3 (n) = (1000001 ∗ 10−6 )n – O((1.000001)n )


3.
f4 (n) = n! – O(n!)

7 7
4. f5 (n) = 210∗10
5. 10·10
√ – O(21.5 )
f6 (n) = n ∗ n – O(n )

2
√ √
n n – O(n n )
6. f7 (n) = P
n
f8 (n) = i=1 (i + 1) – O((n+1)!)

So in increasing order of asymptotic complexity, we get the following sequence of functions:

7. f1 (n) = n0.999 log2 (n)


1.
2. f2 (n) = 107 ∗ n

3. f6 (n) = n ∗ n

n
4. f7 (n) = n
5. f3 (n) = (1000001 ∗ 10−6 )n
Pn
6. f8 (n) = i=1 (i + 1)
7
7. f5 (n) = 210∗10
8. f4 (n) = n!

The graphs are plotted with Desmos and shown as follows:

(a) Equations (b) Graph

Figure 1: Equations and their corresponding graphs

3
Solution to Task 2
Find only the complexity for findJthelement function.
The code is written as follows:

def findJthelement(j, a):


if j >= len(a):
return -1
for i in range(j, len(a)):
return a[j]

print(findJthelement(3, [1, 2, 3, 4, 5]))

The function determines whether j is larger or equal to the length of a. If true, it returns -1. This
check’s time complexity is constant, represented as O(1).
If the preceding condition is false, the function starts a loop that goes from j to the length of a.
Within the loop, the function returns a[j]. The time complexity of this loop is O(n - j), where n is
a’s length and j is the starting index.
Because we are only interested in the worst-case time complexity, we assign the loop’s complexity
to O(n). The findJthelement function has an overall temporal complexity of O(n).

Find complexity for both arr and arr1


The code is written as follows
def searchAlgo(arr, x):
low = 0
high = len(arr) - 1
mid = 0

while low <= high:


mid = (high + low) // 2

if arr[mid] < x:
low = mid + 1
elif arr[mid] > x:
high = mid - 1
else:
return mid

return -1

arr = [5, 2, 4, 10, 6, 1, 3]


arr.sort() # Python uses Timsort, which has a time complexity of O(n log n)
arr1 = [1, 2, 3, 4, 5, 10]
x = 10
print(searchAlgo(arr1, x))

4
By analysing the time complexity for both arr and arr1 scenarios:
For arr:

The supplied array is sorted using the Timesort algorithm (arr.sort()). Timesort’s time complex-
ity is O(n log n). Following sorting, the binary search is performed, which has a time complexity of
O(log n).

As a result, the search in arr has an overall time complexity of O(n log n).

For arr1:

The given arr1 is already sorted, therefore the binary search is performed directly. Binary search
has a time complexity of O(logn).
As a result, the search in arr1 has an overall time complexity of O(log n).

Find only the complexity for build function.


The code is written as follows:
def build(a, v, tl, tr):
if tl == tr:
t[v] = a[tl]
else:
tm = (tl + tr) // 2
build(a, v * 2, tl, tm)
build(a, v * 2 + 1, tm + 1, tr)
t[v] = t[v * 2] + t[v * 2 + 1]

a = [1, 2, 3, 4, 5, 6, 7, 8]
t = [0 for _ in range(4 * len(a))]
build(a, 1, 0, len(a) - 1)
print(t)

The time complexity of the ’build’ function in the provided code is O(n), where n represents the
length of the input array ’a’.
The reason for this is that the ’build’ function visits each element of the input array ’a’ exactly
once. At each recursive call, the function divides the array it is presently working on into two halves
until it reaches individual elements, at which point it begins merging them back together to update
the tree nodes. The entire number of operations is proportional to the array’s number of elements,
hence the time complexity is O(n).

5
Solution to Task 3
A binary search-based approach can be used to discover a peak in a 2D matrix that meets the
required constraints. The idea is to discover the highest element in the middle column and then
compare it to its neighbors to see if it is a peak. If it is not a peak, go to the side with the taller
neighbor. Repeat the technique until you reach a peak.
The Python implementation of this code is written below
def find_peak(matrix):
rows = len(matrix)
columns = len(matrix[0])

def is_valid(x, y):


return 0 <= x < rows and 0 <= y < columns

def binary_search(start_col, end_col):


if start_col > end_col:
return None # No peak found in the current search space

mid_col = (start_col + end_col) // 2

max_row = 0
max_val = matrix[0][mid_col]

for i in range(1, rows):


if matrix[i][mid_col] > max_val:
max_val = matrix[i][mid_col]
max_row = i

# Check if the peak is found


neighbors = [(max_row - 1, mid_col), (max_row + 1, mid_col), (max_row, mid_col - 1), (max_ro
if all(is_valid(x, y) and matrix[max_row][mid_col] >= matrix[x][y] for x, y in neighbors):
return (max_row, mid_col)
elif is_valid(max_row - 1, mid_col) and matrix[max_row - 1][mid_col] > matrix[max_row][mid_c
# Move to the left side
return binary_search(start_col, mid_col - 1)
else:
# Move to the right side
return binary_search(mid_col + 1, end_col)

return binary_search(0, columns - 1)

# Example usage:
matrix1 = [
[0, 1, 0],
[1, 2, 1],
[0, 1, 0]
]

matrix2 = [
[0, 1, 0],
[0, 0, 0],

6
[0, 0, 0]
]

print("Peak in matrix1:", find_peak(matrix1)) # Output: (1, 1)


print("Peak in matrix2:", find_peak(matrix2)) # Output: (0, 1) or (2, 1)

The find peak function takes a 2D matrix as input.The number of rows and columns in the
matrix are initialized by this function.
The is valid function is executed to check whether a given coordinate (x, y) is at the the bounds of
the provided matrix.
The function performing binary search is executed on the columns to find a peak. The start and
end columns are considered as parameters to define the current search space.
If start col > end col, the search space is empty, and the function returns None, implying that
no peak was discovered. Otherwise, it computes the middle column (mid col) and searches for the
highest element in that column, along with its row index. It determines whether the element at
(max row, mid col) is a peak by comparing it to its neighbors. If the function finds a peak, it
returns the coordinates (max row, mid col). If there isn’t a peak, the function searches the left or
right side based on how the element compares to its neighbors.

You might also like