L
L
lutokris2021-12-27 14:55:41
Python
lutokris, 2021-12-27 14:55:41

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

3 answer(s)
V
Vindicar, 2021-12-27
@lutokris

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]

True, this will give an incorrect result if the list does not contain zeros. But this can be detected during the first pass.

D
dmshar, 2021-12-27
@dmshar

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)

Result:
[2, 1, 0, 1, 0, 1, 2, 3, 2, 1, 0, 0, 1, 2, 3, 4
]
m_l=[len(lst)]*len(lst)
and
m_l.append(m)
replace with
m_l[i]=m
Due to the statics of working with the list, it should turn out even faster.

A
Alexandroppolus, 2021-12-27
@Alexandroppolus

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 question

Ask a Question

731 491 924 answers to any question