Я не знаю, можно ли это сделать лучше, но я думаю, что следующий алгоритм дает правильный ответ:
def num_move_end_sort(lst):
# dict that maps each list element to its index in the sorted list
sorted_index = {elem: i for i, elem in enumerate(sorted(lst))}
moves = 0
for idx, elem in enumerate(lst):
if idx != sorted_index[elem] + moves:
moves += 1
return moves
print(num_move_end_sort([5, 1, 3, 2, 7]))
# 3
Идея состоит в следующем.Каждый элемент списка должен быть перемещен до конца не более одного раза (должно быть легко увидеть, что решение, которое перемещает один и тот же элемент в конец более одного раза, может быть упрощено).Таким образом, каждый элемент в списке может или не может быть перемещен один раз до конца.Если элемент не нужно перемещать, это потому, что после всех ходов он оказался в правильном положении.Таким образом, если элемент в данный момент находится в позиции i
и должен в конечном итоге оказаться в позиции j
, то элемент не нужно будет перемещать, если число предыдущих элементов, которые необходимо переместить, n
, удовлетворяет j == i + n
(потому что после этих n
перемещений элемент действительно будет в позиции j
).
Итак, чтобы вычислить это, я отсортировал список и взял индексы каждого элемента в отсортированномсписок.Затем вы просто подсчитываете количество элементов, которые не находятся в правильном положении.
Обратите внимание, что этот алгоритм не сообщает вам фактическую последовательность шагов, которые вам нужно будет выполнить (порядок, в котором элементы должны бытьпереехал), только граф.Сложность O (n · log (n)) (из-за сортировки).