Would this function be o(n) time complexity? - python

I'm currently in a data structures class, would this function be considered O(N)? My thinking was due to the while loop not having a direct correlation to the for loop, it's still O(N)? If more information/code is needed for better context, I don't mind editing the post.
I appreciate any clarification.
input_array = [7, 3, 4, 1, 8]
new_min_heap = []
for index in range(0, len(input_array)):
val = input_array[index]
new_min_heap.append(val)
# if new_min_heap has other values, start swappin
if len(new_min_heap) > 1:
parent_index = get_parent_index(index)
parent_val = new_min_heap[parent_index]
while val < parent_val:
new_min_heap.swap(index, parent_index)
val = parent_val
parent_index = get_parent_index(parent_index)
parent_val = new_min_heap[parent_index]

I assume the n is the size of the input array.
The for loop has the O(n) complexity since it is executed n times. The inner while loop exchanges the values between the current array element and it's ancestors. It is executed at most lg(n) times, so the complexity is O(lg(n)). Thus, the total complexity is O(n lg(n)).

If with "swap value and parent_value", you mean:
value, parent_value = parent_value, value
Then, the while loop will be O(1) (in case there isn't any other loop inside the while loop)
So the whole function will be O(n) based on the array length
Maybe if you bring us more context the answer could change.

Related

Python Find the mean school assignment - What is a loop?

I have been working on this assignment for about 2 weeks and have nothing done. I am a starter at coding and my teacher is really not helping me with it. She redirects me to her videos that I have to learn from every time and will not directly tell or help me on how I can do it. Here are the instructions to the assignment (said in a video, but made it into text.
Find the mean
Create a program that finds the mean of a list of numbers.
Iterate through it, and instead of printing each item, you want to add them together.
Create a new variable inside of that, that takes the grand total when you add things together,
And then you have to divide it by the length of your array, for python/java script you’ll need to use the method that lets you know the length of your list.
Bonus point for kids who can find the median, to do that you need to sort your list and then you need to remove items from the right and the left until you only have one left
All you’re doing is you need to create a variable that is your list
Create another variable that is a empty one at the moment and be a number
Iterate through your list and add each of the numbers to the variable you created
Then divide the number by the number of items that you had in the list.
Here's what I've done so far.
num = [1, 2, 3, 4, 5, 6];
total = 0;
total = (num[0] + total)
total = (num[1] + total)
total = (num[2] + total)
total = (num[3] + total)
total = (num[4] + total)
total = (num[5] + total)
print(total)
However, she tells me I need to shorten down the total = (num[_] + total) parts into a loop. Here is how she is telling me to do a loop in one of her videos.
for x in ____: print(x)
or
for x in range(len(___)): print (x+1, ____[x])
there is also
while i < len(___):
print(___[i])
i = i + 1
I really don't understand how to do this so explain it like I'm a total noob.
First of all, loops in python are of two types.
while: a while loop executes the code in a body until a condition is true. For example:
i = 0
while(i < 5):
i = i + 1
executes i = i + 1 until i < 5 is true, meaning that when i will be equal to 5 the loop will terminate because its condition becomes false.
for: a for loop in python iterates over the items of any sequence, from the first to the last, and execute its body at each iteration.
Note: in both cases, by loop body I mean the indented code, in the example above the body is i = i + 5.
Iterating over a list. You can iterate over a list:
Using an index
As each position of the array is indexed with a positive number from 0 to the length of the array minus 1, you can access the positions of the array with an incremental index. So, for example:
i = 0
while i < len(arr):
print(arr[i])
i = i + 1
will access arr[0] in the first iteration, arr[1] in the second iteration and so on, up to arr[len(arr)-1] in the last iteration. Then, when i is further incremented, i = len(arr) and so the condition in the while loop (i < arr[i]) becomes false. So the loop is broken.
Using an iterator
I won't go in the details of how an iterator works under the surface since it may be too much to absorb for a beginner. However, what matters to you is the following. In Python you can use an iterator to write the condition of a for loop, as your teacher showed you in the example:
for x in arr:
print(x)
An iterator is intuitively an object that iterates over something that has the characteristic of being "iterable". Lists are not the only iterable elements in python, however they are probably the most important to know. Using an iterator on a list allows you to access in order all the elements of the list. The value of the element of the list is stored in the variable x at each iteration. Therefore:
iter 1: x = arr[0]
iter 2: x = arr[1]
...
iter len(arr)-1: x = arr[len(arr)-1]
Once all the elements of the list are accessed, the loop terminates.
Note: in python, the function range(n) creates an "iterable" from 0 to n-1, so the for loop
for i in range(len(arr)):
print(arr[i])
uses an iterator to create the sequence of values stored in i and then i is in turn used on the array arr to access its elements positionally.
Summing the elements. If you understand what I explained to you, it should be straightforward to write a loop to sum all the elements of a list. You initialize a variable sum=0 before the loop. Then, you add the element accessed as we saw above at each iteration to the variable sum. It will be something like:
sum = 0
for x in arr:
sum = sum + x
I will let you write an equivalent code with the other two methods I showed you and do the other points of the assignment by yourself. I am sure that once you'll understand how it works you'll be fine. I hope to have answered your question.
She wants you to loop through the list.
Python is really nice makes this easier than other languages.
I have an example below that is close to what you need but I do not want to do your homework for you.
listName = [4,8,4,7,84]
for currentListValue in listName:
#Do your calculating here...
#Example: tempVar = tempVar + (currentListValue * 2)
as mentioned in the comments w3schools is a good reference for python.

optimizing code running time [diffrence between the codes below]

these are two codes, can anyone tell me why the second one takes more time to run.
#1
ar = [9547948, 8558390, 9999933, 5148263, 5764559, 906438, 9296778, 1156268]
count=0
big = max(ar)
for i in range(len(ar)):
if(ar[i]==big):
count+=1
print(count)
#2
ar = [9547948, 8558390, 9999933, 5148263, 5764559, 906438, 9296778, 1156268]
list = [i for i in ar if i == max(ar)]
return len(list)
In the list comprehension (the second one), the if clause is evaluated for each candidate item, so max() is evaluated each time.
In the first one, the maximum is evaluated once, before the loop starts. You could probably get a similar performance from the list comprehension by pre-evaluating the maximum in the same way:
maxiest = max(ar)
list = [i for i in ar if i == maxiest]
Additionally, you're not creating a new list in the first one, rather you're just counting the items that match the biggest one. That may also have an impact but you'd have to do some measurements to be certain.
Of course, if you just want to know what the difference between those two algorithms are, that hopefully answers your question. However, you should be aware that max itself will generally pass over the data, then your search will do that again. There is a way to do it with only one pass, something like:
def countLargest(collection):
# Just return zero for empty list.
if len(collection) == 0: return 0
# Setup so first item is largest with count one.
count = 0
largest = collection[0]
# Process every item.
for item in collection:
if item > largest:
# Larger: Replace with count one.
largest = item
count = 1
elif item == largest:
# Equal: increase count.
count += 1
return count
Just keep in mind you should check if that's faster, based on likely data sets (the optimisation mantra is "measure, don't guess").
And, to be honest, it won't make much difference until either your data sets get very large or you need to do it many, many times per second. It certainly won't make any real difference for your eight-element collection. Sometimes, it's better to optimise for readability rather than performance.

Using a selection sort to sort an array in python. How can I optimize?

Working on this challenge on HackerRank and got this code to pass 10 out of 15 test cases. It is failing due to timeout error which is HackerRank's way of telling you that the algorithm is not optimized. How can I optimize this code to run on larger input data?
The goal is to figure out the minimum number of swaps necessary to sort an unsorted array.
Update: Each element in the array is distinct.
def minimum_swaps(arr):
"""Returns the minimum number of swaps to re-oder array in ascending order."""
swaps = 0
for val in range(len(arr) - 1, 0, -1):
# Index of max value
max_pos = 0
for index in range(1, val + 1):
if arr[index] > arr[max_pos]:
max_pos = index
# Skip if value is already in sorted position
if max_pos == val:
continue
arr[val], arr[max_pos] = arr[max_pos], arr[val]
swaps += 1
return swaps
Look at the code. It has 2 nested loops:
The outer loop iterates over the positions val.
The inner loop finds the index of the value that should be at the index val, i.e., max_pos.
It takes a lot of time just to find the index. Instead, I will compute the index of each value and store it in a dict.
index_of = {value: index for index, value in enumerate(arr)}
(note that because all values in arr are distinct, there should be no duplicated keys)
And also prepare a sorted version of the array: that way it's easier to find the maximum value instead of having to loop over the array.
sorted_arr = sorted(arr)
Then do the rest similar to the original code: for each index visited, use sorted_arr to get the max, use index_of to get its current index, if it's out-of-place then swap. Remember to update the index_of dict while swapping too.
The algorithm takes O(n) operations (including dict indexing/modifying), plus sorting cost of n elements (which is about O(n log n)).
Note: If the array arr only contains integers in a small range, it may be faster to make index_of an array instead of a dict.
The short answer is: implement merge sort. The bubble sort algorithm you are using has a O(n^2) running time, while merge sort has a O(log_2(n)) running time.

i want to find out the index of the elements in an array of duplicate elements

a=[2, 1, 3, 5, 3, 2]
def firstDuplicate(a):
for i in range(0,len(a)):
for j in range(i+1,len(a)):
while a[i]==a[j]:
num=[j]
break
print(num)
print(firstDuplicate(a))
The output should be coming as 4 and 5 but it's coming as 4 only
You can find the indices of all duplicates in an array in O(n) time and O(1) extra space with something like the following:
def get_duplicate_indices(arr):
inds = []
for i, val in enumerate(arr):
val = abs(val)
if arr[val] >= 0:
arr[val] = -arr[val]
else:
inds.append(i)
return inds
get_duplicate_indices(a)
[4, 5]
Note that this will modify the array in place! If you want to keep your input array un-modified, replace the first few lines in the above with:
def get_duplicate_indices(a):
arr = a.copy() # so we don't modify in place. Drawback is it's not O(n) extra space
inds = []
for i, val in enumerate(a):
# ...
Essentially this uses the sign of each element in the array as an indicator of whether a number has been seen before. If we come across a negative value, it means the number we reached has been seen before, so we append the number's index to our list of already-seen indices.
Note that this can run into trouble if the values in the array are larger than the length of the array, but in this case we just extend the working array to be the same length as whatever the maximum value is in the input. Easy peasy.
There are some things wrong with your code. The following will collect the indexes of every first duplicate:
def firstDuplicate(a):
num = [] # list to collect indexes of first dupes
for i in range(len(a)-1): # second to last is enough here
for j in range(i+1, len(a)):
if a[i]==a[j]: # while-loop made little sense
num.append(j) # grow list and do not override it
break # stop inner loop after first duplicate
print(num)
There are of course more performant algorithms to achieve this that are not quadratic.

Python selection sort algorithm returns only a list of minimum value

def sortList(self, list):
for i in range(len(list)):
min = list[i]
for j in range(i+1, len(list)):
if list[j] < min:
min = list[j]
list[i] = min
return list
The above algorithm returns a list the minimum value. For example, if the sample list is list = [4,7,9,2], the algorithm will return [2,2,2,2].
Where is the fault in the algorithm?
Well there are some mistakes here:
first of all, you calculate min in a weird way, since you each time assign it to list[i]; and
you do not "swap" you simply assign the minimum to that part of the list.
What you basically need is an algorithm that each time calculates the minimum between i and the end of the list, and then either "shift" the other elements to the right, or perform a swap with the element that occupies the place where you want to put that element.
I think the latter (swapping) is a tiny bit more efficient, since it is an O(1) operation (but mind that finding the minimum is an O(n) opeation.
So you can use:
def sort_list(self,data):
n = len(data) # obtain the length of the list
for i in range(n):
min, minj = data[i], i # we use data[i] as the running min
# i as index of the smallest item
for j in range(i+1,n): # iterate over the remainder of the list
if data[j] < min: # if we find a smaller item
min, minj = data[j], j # update min and minj
# perform a swap between i and minj
t = data[i]
data[i] = min
data[minj] = t
return data
That being said insertion sort is definitely not the most efficient sorting algorithm, you better use the builtin list.sort method, or sorted function which are optimized for Python.

Categories