-
Notifications
You must be signed in to change notification settings - Fork 0
/
BigO.py
158 lines (122 loc) · 5.22 KB
/
BigO.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"""
BigO Notation
Big O Notation is used to measure hoe running time or space requirements for your program grow as input size grows
Order of Magnitude
A Time Complexity does not tell the exact number of times the code inside a loop is executed,
but it only shows the order of magnitude. Whether code inside loop is executed for 3n, n+5, n/2 times;
the time complexity of each code is O(n)
Rules for BigO Notation
time = a * n + b
> Keep fastest growing term
BigO refers to very large value of n. Hence if you have a function like:
time = 5*n^2 + 3*n + 20
when value of n is very large (b*n + c) become irrelevant
Example: n = 1000
time = 5*1000^2 + 3*1000 + 20
time = 5000000 + 3020
time ~= 5000000 # terms other than 5*1000^2 contribute negligible
time = a * n # being b a constant and static
> Drop constant
time = n # a being constant
time = O(n)
Measuring running time growth (Time Complexity)
Constant Time Complexity O(1)
Running time of Constant-time algorithm does not depend on the input size
time = a
time = O(1) # applying rules for Big O :: Keep fastest growing term (a) ->->-> Drop Constants(a)
def foo(a): # time is nearly constant with increase in input size
size(arr) : 100 -> 0.22 milliseconds
size(arr) : 1000 -> 0.23 milliseconds
Logarithmic Time Complexity O(log n)
A logarithmic algorithm often halves the input size at each step. The running time of such an algorithm is
logarithmic, because log2 n equals the number of times n must be divided by 2 to get 1
Square Root Algorithm O(sqrt(n))
A square root algorithm is slower than O(log n) but faster than O(n) A special property of square roots is that
sqrt(n) = n/(sqrt(n)), so the square root (sqrt(n)) lies, in some sense, in the middle of the input
Linear Time Complexity O(n)
A linear algorithm goes through the input a constant number of times
time = a * n + b
time = O(n) # applying rules for Big O :: Keep fastest growing term (a*n) ->->-> Drop Constants(a, b)
def foo(arr):
size(arr) : 100 -> 0.22 milliseconds
size(arr) : 1000 -> 2.30 milliseconds
O(n log n)
This time complexity often indicates that the algorithm sorts the input, because the time complexity of
efficient sorting algorithms is O(n logn)
Quadratic Time Complexity O(n^2)
A quadratic time complexity often contains two nested loops
time = a * (n^2) + b
time = O(n^2) # applying rules for Big O :: Keep fastest growing term (a*n^2) ->->-> Drop Constants(a, b)
Exception O(n^2) not O(n^2 + n)
time = a*(n^2) + (b * n) + c
time = n^2 # applying rules for Big O :: Keep fastest growing term (a*n^2) ->->-> Drop Constants(a, b, c)
Cubic Time Complexity O(n^3)
A cubic algorithm often contains three nested loops
O(2^n)
This time complexity often indicates that the algorithm iterates through all subsets of the input elements
O(n!)
This time complexity often indicates that the algorithm iterates through all permutations of the input elements
Note:
An algorithm is polynomial if its time complexity is at most O(nk) where k is a constant.
All the above time complexities except O(2n) and O(n!) are polynomial
Given the input size, we can try to guess the required time complexity of the algorithm that solves the problem.
The following table contains some useful estimates assuming a time limit of one second
n <= 10 O(n!)
n <= 20 O(2n)
n <= 500 O(n3)
n <= 5000 O(n2)
n <= 106 O(n logn) or O(n)
n is large O(1) or O(log n)
"""
""" Time Complexity """
# Linear Time Complexity O(n)
def squareNum(numbers):
"""
Time Complexity: O(n) :: loop will iterate n time linearly
"""
sqNum = [] # empty array for squared numbers initialised
for n in numbers: # loop will iterate n times
sqNum.append(n*n)
return sqNum
# Constant Time Complexity O(1)
def findPE(prices, eps, index):
pe = prices[index] / eps[index]
return pe
# O(n^2)
def duplicateInArray(numbers):
""" Running two for loops"""
duplicate = None
# (n^2) iterations
for i in range(len(numbers)):
for j in range(i+1, len(numbers)):
if numbers[i] == numbers[j]:
print(f"{numbers[i]} is duplicate")
duplicate = numbers[i]
break
# n iterations
for i in range(len(numbers)):
if numbers[i] == duplicate:
print(i)
""" Space Complexity """
def Search(numbers):
"""
Search for 10 in list
Time Complexity: O(n)
"""
for i in range(len(numbers)):
if numbers[i] == 10:
print(i)
if __name__ == '__main__':
# O(n)
numbers = [2, 5, 7, 9]
print(squareNum(numbers))
# O(1)
prices = [250, 500, 450]
eps = [25, 50, 75]
index = 1
print(findPE(prices, eps, index))
# O(n^2)
numbers = [2, 4, 6, 8, 14, 9, 4]
duplicateInArray(numbers)
numbers = [1, 6, 8, 10, 4, 5]
Search(numbers)