Answer the question
In order to leave comments, you need to log in
How to speed up the algorithm a little more?
All good. I solve a problem by determining the distance to the nearest zero in the elements of the list. Let's say there is a list of the form 5 3 0 2 0 3 and the output should be 2 1 0 1 0 1. Of course, I went a little "strange" way - but decided to go all the way and do it in this form. Of course, everything works for me, I spend a minimum of memory, but I do not fit into the allotted time by 0.77 seconds. I just can’t understand in which part of the code what should I optimize in order to win another 0.77 seconds (
def know_range(n):
result = []
half = n // 2
if n == 1:
result.append(1)
return result
result += [x for x in range(1, half+1)]
if n & 1: # если нечетный
result.append(half+1)
result += [x for x in range(half, 0, -1)]
return result
def file_read_to_byte_discrete(f_path):
res_arr = 0b0
len_arr = 0b0
n = 0
with open(f_path) as f:
n = int(f.readline()) + 1
len_arr = 0b1 << n
buf = ""
#for i in f.read():
i = " "
while i != "":
i = f.read(1)
if i != " " and i != "":
buf+= i
else:
if int(buf) | 0:
res_arr = res_arr | 1
else:
res_arr = res_arr | 0
res_arr = res_arr << 1
buf = ""
f.close()
res_arr = len_arr + res_arr
res_arr = res_arr >> 1
return res_arr
byte_arr = file_read_to_byte_discrete('input.txt')
n = len(bin(byte_arr)) - 3
result_arr = []
number = 0
# проверим левый край если там не ноль
left_null = 0
if ((byte_arr >> n-1) & 1):
number = 0
for i in range(n-1, -1, -1):
if not ((byte_arr >> i) & 1): # если найдем нолик выходим
if number != 0:
left_null = number
else:
left_null = 1
break
else:
number += 1
if number != 0:
for i in range(number, 0, -1):
result_arr.append(i)
number = 0
for i in range(n-1-left_null, -1, -1):
if not ((byte_arr >> i) & 1):
# найден нолик
if number != 0:
result_arr = result_arr + know_range(number)
result_arr.append(0)
number = 0
else:
number += 1
# проверим правый край если там не ноль просто печатаем номера
if (byte_arr & 1):
result_arr += [x for x in range(1, number+1)]
for el in result_arr:
print(el, end=" ")
Answer the question
In order to leave comments, you need to log in
Wouldn't it be easier to do it in two passes?
In a direct pass, we do this: if 0, then the counter is zero, otherwise the counter + 1 and the element is equal to the counter.
Then we do the same in reverse, but change the element only if it is greater than the counter.
From here we get:
lst=[5, 3, 0, 2, 0, 3, 8, 2, 9, 7, 0, 0, 7, 1, 5, 3]
L = len(lst)
# если в начале списка не 0, то мы сможем задать корректные значения только на обратном ходе
# так что ставим заведомо большее значение счетчика
counter = len(lst) if lst[0] != 0 else 0
for i in range(0, L):
if lst[i] == 0:
counter = 0
else:
counter += 1
lst[i] = counter
# обратный ход
counter = lst[-1] - 1 #чтобы не запороть последние элементы
for i in range(L-1, -1, -1):
if lst[i] == 0:
counter = 0
else:
counter += 1
lst[i] = min(counter, lst[i])
print(lst)
# [2, 1, 0, 1, 0, 1, 2, 3, 2, 1, 0, 0, 1, 2, 3, 4]
Wouldn't it be faster like this?
(Example specially complicated)
lst=[5, 3, 0, 2, 0, 3, 8, 2, 9, 7, 0, 0,7,1, 5, 3]
l=[i for i,v in enumerate(lst) if v == 0]
m_l=[]
for i,ls in enumerate(lst):
m=len(lst)
for j in l:
if m>abs(i-j):
m=abs(i-j)
m_l.append(m)
print (m_l)
m_l=[len(lst)]*len(lst)
m_l.append(m)
m_l[i]=m
The path is really strange. And most importantly, there are some incomprehensible actions with an array that may lead to copying, for example, result_arr = result_arr + know_range(number) The
easiest way would be to get an array from a string with increasing non-zero intervals, and then walk through it from right to left and "cut corners":
string "5 3 0 4 6 1 5 0 9 2 3 0"
array after first iteration: [inf, inf, 0, 1, 2, 3, 4, 0, 1, 2, 3, 0]
after reverse traversal, same array: [2, 1, 0, 1, 2, 2, 1, 0, 1, 2, 1, 0]
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question