Python - List sorting & Asymptotic Complexity - python

I have a list arr and a value dif. I need to create an algorithm that will go through the values in arr, subtract them (the largest value after subtraction can be maximally dif) and then output the resulting values in new lists.
I created this code. The first problem is that it is broken if there are 3+ lists in the output. The second problem is the time complexity - if I'm not mistaken, it is O(n^2) so it's really slow.
I've tried to create this using Insertion sort and Binary search, but I never get the right result. The output was even worse than in the above code.
Can someone help me? How to simplify the algorithm and how to make it work correctly?
Code :
arr = [9, 3, 11, 5, 10, 4]
arr2 = [16, 13, 3, 1, 8, 2]
dif = 3
def func(arr):
pre_list = []
for i in range(0, len(arr)):
result = []
for j in range(0, len(arr)):
sub = arr[i] - arr[j]
if (abs(sub) <= dif):
result.append(arr[j])
if (result not in pre_list):
pre_list.append(result)
print(result)
func(arr)
Output:
arr:
[9, 11, 10]
[3, 5, 4]
arr 1:
[16, 13]
[3, 1, 2]
[8]

Related

How do you check if an item in a list is greater than all the items before it in the list?

I'm trying to check and loop through a list of numbers to see if all the numbers before than number in the list are less than that number for all the items in the list. This is what I've tried so far:
myList = [5, 8, 2, 3, 10, 7, 12]
numberList = []
for number in myList:
if number > myList[myList.index(number) - 1]:
numberList.append(number)
However, this only checks the number right before it in the list, not all the numbers before it. I was wondering if there was a way to fix this or a better way to approach this. The output I've been getting is [5, 8, 3, 10, 12], not [5, 8, 10, 12] like I want.
Just track the maximum:
myList = [5, 8, 2, 3, 10, 7, 12]
numberList = []
maxx = -1
for number in myList:
if number > maxx:
numberList.append(number)
maxx = number
Use list comprehension. The walrus operator := is available in python 3.8 onwards, and is ideal for your case:
max = mylist[0]
[max := each for each in myList if each > max]

How can I compute distances between elements in a list and get a "sorted and without duplicate" list in return?

Let's say I have the following list:
[1, 2, 6, 8, 9, 12, 14]
I want to compute distances between element of this list so that:
∀i ∈ [0, . . . , s − 2], D(i) = O(i + 1) − O(i)
so the list of distances would be :
[1, 4, 2, 1, 3, 2]
Last step, I want this list of distances to be sorted and without duplicate, so the final result would be:
[1, 2, 3, 4]
What would be the most efficient way to do so ?
So far I have the following code:
for i in range(0, len(elements) - 1):
distances.append(elements[i + 1] - elements[i])
lst_output = list(set(distances))
lst_output.sort()
It works but there must be better ways to do this, using lambda function I suppose.
How would you do so ?
I believe more efficient solution is to add the items immediately to the set:
s = set()
for i in range(len(elements) - 1):
s.add(elements[i+1] - elements[i])
lst_output = list(s) # this is already sort
this might me faster:
elements = [1, 2, 6, 8, 9, 12, 14]
distances = []
for i in range(0, len(elements) - 1):
distances.append(elements[i + 1] - elements[i])
distances.sort()
print(distances)
i = 0
while i < len(distances)-1:
while distances[i] == distances[i + 1]:
distances.pop(i)
i += 1
print(distances)
I think that the best solution for you would be to use dict as follow:
elements = [1, 2, 6, 8, 9, 12, 14]
distances = []
for i in range(0, len(elements) - 1):
distances.append(elements[i + 1] - elements[i])
final_lst_output= list(dict.fromkeys(distances))
print(sorted(final_lst_output))
which will give you
[1, 2, 3, 4]
Assuming that you want to have both the basic difference list and the non-duplicate sorted differences, you can get them compactly:
distances = [ thisel - elements[i] for i,thisel in enumerate(elements[1:]) ]
lst_output = sorted(set(distances))
Notice that the list comprehension starts at the second element of elements ([1]), but since the enumerate will start at 0 the difference is between successive values. If the distances list is not needed, the comprehension can go into the set constructor.
Generally list comprehensions are efficient. If maintainability is important and this code might be misunderstood, the simple loop generation of distance might be better.

Sum of parts in a list

I wrote this code:
arr = [1, 2, 3, 4, 5, 6]
arr1 = []
count = 0
arr.append(0) # i forgot to wrote this line.
for i in range(0, len(arr)):
count = sum(arr)
arr.remove(arr[0])
arr1.append(count)
print(arr1)
The output is:
[20, 20, 19, 16, 10, 0]
But I have a little problem. Time of execution it is a little bit to long for large lists.
Can u tell me if exist another mode to write it?
Thx!
I'd suggest itertools.accumulate
from itertools import accumulate
from operator import add
result = list(accumulate(reversed(arr), add))[::-1]
With a few test it's a lot more performant, for 20k digits
accumulate 0:00:00.004001
question 0:00:05.340281
In python, removing the first element of a list requires all the subsequent elements to be moved and therefore takes O(n). Since you're doing that n times (with n being the length of your array), the overall time complexity of your solution is O(n2)
Any solution that only runs in O(n) time complexity should be fine for you. Here is one that doesn't require any external imports and is similar in style to your original solution:
arr = [1, 2, 3, 4, 5, 6]
total = sum(arr)
sums = [total]
for to_remove in arr[:-1]:
total -= to_remove
sums.append(total)
print(sums)
[21, 20, 18, 15, 11, 6]
It is not perfect but a little faster:
import timeit
def function():
arr = [1, 2, 3, 4, 5, 6]
arr1 = []
count = 0
for i in range(0, len(arr)):
count = sum(arr)
arr.remove(arr[0])
arr1.append(count)
return arr1
print(timeit.timeit(function))
Time: 1.9620031519999657
import timeit
def function():
arr = [1, 2, 3, 4, 5, 6]
arr1 = [sum(arr)]
i = 0
while i < len(arr)-1:
arr1.append(arr1[i] - arr[i])
i = i +1
arr1.append(arr1[-1]-arr[-1])
return arr1
print(timeit.timeit(function))
Time: 1.408351424999978
If you are every time conscious, always try to use libraries like numpy.
In numpy this will be every easy, and efficient.
import numpy
a = numpy.arange(7) # since you also want to include 6 in array, 0, 1, 2, ..., 5, 6
np.cumsum(a[::-1])[::-1]
You would need to install numpy separately. If you don't know you can install numpy by:
pip install numpy

How to increase efficiency of comparing elements of a list?

Whenever I code on online platforms and somehow I have to compare the elements of a list to one another, I use the following code which according to me is the most efficient possible. This is the last code which I was practicing. It was to find the maximum index between 2 same elements.
max=0
for i in range(len(mylist)):
if max==(len(mylist)-1):
break
for j in range(i + 1, len(mylist)):
if mylist[i] == mylist[j]:
if max>(abs(i-j)):
max=abs(i-j)
It runs most of the test cases, but sometimes it shows "time limit exceeded." I know it is related to the constraints and time complexity but I still can't find a better way. If anyone could help me, that would be great.
It's easier to use C based functions in Python. Also don't name variables python types like list.
x = [item for i, item in enumerate(l) if item in l[i+1:]]
# do something with list of values
You could group by equal elements and then find the difference in-group, and keep the maximum:
lst = [1, 3, 5, 3, 7, 8, 9, 1]
groups = {}
for i, v in enumerate(lst):
groups.setdefault(v, []).append(i)
result = max(max(group) - min(group) for group in groups.values())
print(result)
Output
7
The complexity of this approach is O(n).
def get_longest_distance_between_same_elements_in_list(mylist):
positions = dict()
longest_distance = 0
if len(mylist) < 1:
return longest_distance
for index in range(0, len(mylist)):
if mylist[index] in positions:
positions[mylist[index]].append(index)
else:
positions[mylist[index]] = [index]
for key, value in positions.items():
if len(value) > 1 and longest_distance < value[len(value)-1] - value[0]:
longest_distance = value[len(value)-1] - value[0]
return longest_distance
l1 = [1, 3, 5, 3, 7, 8, 9, 1]
l2 = [9]
l3 = []
l4 = [4, 4, 4, 4, 4]
l5 = [10, 10, 3, 4, 5, 4, 10, 56, 4]
print(get_longest_distance_between_same_elements_in_list(l1))
print(get_longest_distance_between_same_elements_in_list(l2))
print(get_longest_distance_between_same_elements_in_list(l3))
print(get_longest_distance_between_same_elements_in_list(l4))
print(get_longest_distance_between_same_elements_in_list(l5))
Output -
7
0
0
4
6
Time Complexity : O(n)

Cyclic rotation of array explanation

Premise: My question is not a duplicate of Cyclic rotation in Python . I am not asking how to resolve the problem or why my solution does not work, I have already resolved it and it works. My question is about another particular solution to the same problem I found, because I would like to understand the logic behind the other solution.
I came across the following cyclic array rotation problem (below the sources):
Cyclic rotation in Python
https://app.codility.com/programmers/lessons/2-arrays/cyclic_rotation/
An array A consisting of N integers is given. Rotation of the array means that each element is shifted right by one index, and the last element of the array is moved to the first place. For example, the rotation of array A = [3, 8, 9, 7, 6] is [6, 3, 8, 9, 7] (elements are shifted right by one index and 6 is moved to the first place).
The goal is to rotate array A K times; that is, each element of A will be shifted to the right K times.
which I managed to solve with the following Python code:
def solution(A , K):
N = len(A)
if N < 1 or N == K:
return A
K = K % N
for x in range(K):
tmp = A[N - 1]
for i in range(N - 1, 0, -1):
A[i] = A[i - 1]
A[0] = tmp
return A
Then, on the following website https://www.martinkysel.com/codility-cyclicrotation-solution/, I have found the following fancy solution to the same problem:
def reverse(arr, i, j):
for idx in xrange((j - i + 1) / 2):
arr[i+idx], arr[j-idx] = arr[j-idx], arr[i+idx]
def solution(A, K):
l = len(A)
if l == 0:
return []
K = K%l
reverse(A, l - K, l -1)
reverse(A, 0, l - K -1)
reverse(A, 0, l - 1)
return A
Could someone explain me how this particular solution works? (The author does not explain it on his website)
My solution does not perform quite well for large A and K, where K < N, e.g.:
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
K = 1000
expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
res = solution(A, K) # 1455.05908203125 ms = almost 1.4 seconds
Because for K < N, my code has a time complexity of O(N * K), where N is the length of the array.
For large K and small N (K > N), my solution performs well thanks to the modulo operation K = K % N:
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
K = 999999999999999999999999
expectedRes = [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
res = solution(A, K) # 0.0048828125 ms, because K is torn down to 9 thanks to K = K % N
The other solution, on the other hand, performs greatly in all cases, even when N > K and has a complexity of O(N).
What is the logic behind that solution?
Thank you for the attention.
Let me talk first the base case with K < N, the idea in this case is to split the array in two parts A and B, A is the first N-K elements array and B the last K elements. the algorithm reverse A and B separately and finally reverse the full array (with the two part reversed separately). To manage the case with K > N, think that every time you reverse the array N times you obtain the original array again so we can just use the module operator to find where to split the array (reversing only the really useful times avoiding useless shifting).
Graphical Example
A graphical step by step example can help understanding better the concept. Note that
The bold line indicate the the splitting point of the array (K = 3 in this example);
The red array indicate the input and the expected output.
Starting from:
look that what we want in front of the final output will be the last 3 letter reversed, for now let reverse it in place (first reverse of the algorithm):
now reverse the first N-K elements (second reverse of the algorithm):
we already have the solution but in the opposite direction, we can solve it reversing the whole array (third and last reverse of the algorithm):
Here the final output, the original array cyclical rotated with K = 3.
Code Example
Let give also another step by step example with python code, starting from:
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
K = 22
N = len(A)
we find the splitting index:
K = K%N
#2
because, in this case, the first 20 shift will be useless, now we reverse the last K (2) elements of the original array:
reverse(A, N-K, N-1)
# [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]
as you can see 9 and 10 has been shift, now we reverse the first N-K elements:
reverse(A, 0, N-K-1)
# [8, 7, 6, 5, 4, 3, 2, 1, 10, 9]
And, finally, we reverse the full array:
reverse(A, 0, N-1)
# [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]
Note that reversing an array have time complexity O(N).
Here is a very simple solution in Ruby. (scored 100% in codility)
Remove the last element in the array, and insert it in the beginning.
def solution(a, k)
if a.empty?
return []
end
modified = a
1.upto(k) do
last_element = modified.pop
modified = modified.unshift(last_element)
end
return modified
end

Categories

Resources