Ошибка в написании алгоритма лексикографической сортировки для списка

Задача:

Натуральные числа от 1 до N упорядочены лексикографически. Например, для N=25 результат этого упорядочения будет таким: 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21, 22, 23, 24, 25, 3, 4, 5, 6, 7, 8, 9.

Требуется написать программу, которая определит, на каком месте оказалось число K.

Входные данные

Входной файл INPUT.TXT содержит два натуральных числа N и K, записанных через пробел (1 ≤ K ≤ N ≤ 10**4).

Выходные данные

Выходной файл OUTPUT.TXT должен содержать одно натуральное число – номер места, на котором оказалось число K.

Например:

Вход: 25 17

Выход: 9

Причина: элемент 17 в списке

[1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21, 22, 23, 24, 25, 3, 4, 5, 6, 7, 8, 9]

находился под номером 9

Мой код:

def lexicographic_sort(arr: list[int]) -> list[int]:
    if len(arr) < 2:
        return arr
    mid = arr[len(arr) // 2]
    l = [i for num, i in enumerate(arr) if str(i) < str(mid) and num != len(arr) // 2]
    r = [i for num, i in enumerate(arr) if str(i) > str(mid) and num != len(arr) // 2]
    return lexicographic_sort(l) + [mid] + lexicographic_sort(r)


n, k = map(int, input().split())
include_list = list(range(1, n + 1))
arr_lexicographic = lexicographic_sort(include_list)
print(arr_lexicographic.index(k) + 1)

Проблема

Один из тестов на сайте не проходит. Где ошибка и как её исправить, чтобы программа работала корректно? Конечно, проще сделать код так и он пройдёт тесты (проверенно):

n, k = map(int, input().split())
include_list = list(range(1, n + 1))
include_list.sort(key=lambda x: str(x))
print(include_list.index(k) + 1)

Меня интересует, где в моей сортировке ошибка.

Сайт, на котором я тестирую: https://acmp.ru/asp/do/index.asp?main=task&id_course=2&id_section=12&id_topic=8&id_problem=38


Ответы (2 шт):

Автор решения: Danis

Не знаю почему, но если брать не элемент по середине, а случайный то все тесты проходит:

import random


def lexicographic_sort(arr: list[int]) -> list[int]:
    if len(arr) < 2:
        return arr
    index = random.randrange(len(arr))
    mid = arr[index]
    l = [i for num, i in enumerate(arr) if str(i) < str(mid) and num != index]
    r = [i for num, i in enumerate(arr) if str(i) > str(mid) and num != index]
    return lexicographic_sort(l) + [mid] + lexicographic_sort(r)


n, k = map(int, input().split())
include_list = list(range(1, n + 1))
arr_lexicographic = lexicographic_sort(include_list)
print(arr_lexicographic.index(k) + 1)

Либо же можно брать всегда первый элемент, так тоже прошёл

→ Ссылка
Автор решения: Stanislav Volodarskiy

Алгоритм вы написали правильный. Но у быстрой сортировки есть неприятная особенность, с которой вы и познакомились.

n = 1999 переполняет стек:

$ echo 1999 1 | python lex_sort.py
Traceback (most recent call last):
  File "lex_sort.py", line 12, in <module>
    arr_lexicographic = lexicographic_sort(include_list)
  File "lex_sort.py", line 7, in lexicographic_sort
    return lexicographic_sort(l) + [mid] + lexicographic_sort(r)
  File "lex_sort.py", line 7, in lexicographic_sort
    return lexicographic_sort(l) + [mid] + lexicographic_sort(r)
  File "lex_sort.py", line 7, in lexicographic_sort
    return lexicographic_sort(l) + [mid] + lexicographic_sort(r)
  [Previous line repeated 993 more times]
  File "lex_sort.py", line 5, in lexicographic_sort
    l = [i for num, i in enumerate(arr) if str(i) < str(mid) and num != len(arr) // 2]
  File "lex_sort.py", line 5, in <listcomp>
    l = [i for num, i in enumerate(arr) if str(i) < str(mid) and num != len(arr) // 2]
RecursionError: maximum recursion depth exceeded while getting the str of an object

При первом разбиении mid = 1000. Такое разбиение очень неравновесное. Налево уходят только три числа 1, 10, 100, направо все остальные.

Распечатка лога print(len(l), mid, len(r)):

len(l)     mid  len(r)

     3    1000    1995
     1      10       1
     1    1002    1993
     0    1003    1992
     0    1004    1991
  1990     999       0
     0    1005    1989
  1988     998       0
     0    1006    1987
  1986     997       0
     0    1007    1985
  1984     996       0
     0    1008    1983
  1982     995       0
     0    1009    1981
  1980     994       0
     1    1010    1978
     0    1011    1977
  1976     993       0
     0    1012    1975
...

В середине массива скопились минимальные и максимальные элементы - 999 и ниже очень велики, 1000 и выше очень малы. Почти всегда при разбиении одна половина остаётся пустой. Глубина стека быстрой сортировки становится линейной. Ошибка.

→ Ссылка