Привет, Хабр! Сегодня проверим, какая нейросеть лучше помогает в программировании. На дворе 2025 год у нас подоспел GPT-5.1, подтянулись конкуренты вроде Grok от xAI и DeepSeek из Поднебесной, а на отечественной сцене выступают обновлённая Алиса от Яндекса и сберовский GigaChat.

Одна задача – пять решений

Для теста была выбрана классическая алгоритмическая проблема, с которой любой хоть раз сталкивался: поиск самого длинного палиндрома в строке. Задача сформулирована так: Напиши функцию на Python, которая принимает строку и возвращает самую длинную подстроку-палиндром в этой строке.

Задача достаточно нетривиальная, перебором решать долго, нужно придумать оптимальный подход.

Мы задали всем моделям один и тот же запрос (на русском, чтобы не было форы у англоязычных моделей). Просили решить задачу и предоставить код функции на Python. Затем для каждой полученной функции написал несколько автоматических тестов, разные строки, случаи с несколькими палиндромами, граничные условия.

Решение от GPT-5.1

Начнём с тяжёлой артиллерии. GPT-5.1 получил запрос и буквально через несколько секунд выдал готовое решение. Причём, как показалось, даже слишком готово, с пояснениями и продуманной оптимизацией. Код, который предложил GPT-5.1:

def longest_palindrome(s: str) -> str:

    n = len(s)

    if n < 2:

        return s  # строка длины 0 или 1 сама по себе палиндром

  # Инициализируем переменные для хранения максимального палиндрома

    start = 0

    max_len = 1

    # Матрица dp[i][j] будет True, если подстрока s[i:j+1] является палиндромом

    dp = [[False] * n for _ in range(n)]

    # Все подстроки длиной 1 - палиндромы

    for i in range(n):

        dp[i][i] = True

    # Проверяем подстроки длиной 2

    for i in range(n - 1):

        if s[i] == s[i+1]:

            dp[i][i+1] = True

            start = i

            max_len = 2

    # Проверяем подстроки длиной 3 и более

    for length in range(3, n+1):

        for i in range(0, n-length+1):

            j = i + length - 1

            # Если крайние символы равны и внутренняя подстрока палиндром

            if s[i] == s[j] and dp[i+1][j-1]:

                dp[i][j] = True

                if length > max_len:

                    start = i

                    max_len = length

    return s[start:start + max_len]

GPT-5.1 выбрал динамическое программирование для решения задачи. Чаще известен алгоритм с расширением вокруг центра, он проще реализуется. Но нейросеть пошла серьёзным путём, построила DP-таблицу dp[i][j], где хранит, является ли подстрока s[i:j] палиндромом.

Комментарии присутствуют. Логика такая:

  • Сначала все одиночные буквы отмечаем как палиндромы (это тривиально).

  • Затем отдельно обрабатываем случай подстрок длины 2 (пары символов).

  • Потом постепенно увеличиваем длину length от 3 до n и проверяем все подстроки этой длины. Формула проверки: крайние символы равны s[i] == s[j] и внутренняя подстрока s[i+1:j-1] уже отмечена как палиндром (то есть dp[i+1][j-1] == True).

  • Если условие выполняется, нашли палиндром. Обновляем start и max_len, если он длиннее уже найденного.

  • В конце возвращаем подстроку от start длиной max_len – это и будет самый длинный палиндром.

Решение верное и оптимальное по времен, O(n^2), что для данной задачи считается нормой. Памяти, правда, кушает прилично из-за матрицы, но GPT даже это учёл: использовал компактный dp.

Результат на тестах: идеальный. Я прогнал десяток разных строк – функция от GPT-5.1 во всех случаях нашла правильный палиндром. В том числе на строке "abbaacaab" вернула "abba" (два варианта было – выбрала первый встреченный, что ок), на длинной строке без палиндромов вернула первый символ, и т.д. Никаких ошибок или исключений.

В общем, GPT-5.1 справился на 10/10.

Решение от Grok 3

Теперь посмотрим, что показал Grok. Эта модель доступна через интерфейс X, и у неё репутация дерзкого собеседника. Непонятно, отразится ли эта смелость в коде, но результат порадовал. Grok тоже довольно быстро выдал решение на Python:

def longest_palindrome(s: str) -> str:

    if s == "" or len(s) == 1:

        return s

    longest = s[0]

    for i in range(len(s)):

        # Проверяем нечетные палиндромы (центром является один символ)

        l, r = i, i

        while l >= 0 and r < len(s) and s[l] == s[r]:

 current = s[l:r+1]

            if len(current) > len(longest):

                longest = current

            l -= 1

            r += 1

        # Проверяем четные палиндромы (центром является разрыв между символами)

        l, r = i, i+1

        while l >= 0 and r < len(s) and s[l] == s[r]:

            current = s[l:r+1]

            if len(current) > len(longest):

                longest = current

            l -= 1

            r += 1

    return longest

Как видим, Grok выбрал альтернативный подход, расширение вокруг центра. Это как раз более распространённое решение в задачах на поиск палиндромов. Логика:

  • Пробегаем индекс i по всей строке, рассматривая его как центр палиндрома.

  • Два случая: палиндром нечетной длины (центр – символ s[i]) и чётной длины (центр между s[i] и s[i+1]).

  • Для каждого случая используем два указателя l и r, исходно указывающие на центр (для нечётного палиндрома оба в i, для чётного l = i, r = i+1).

  • Расширяем l влево, r вправо пока символы зеркально равны.

  • Каждый раз, когда нашли палиндром current = s[l:r+1], проверяем его длину – если больше, чем текущий longest, обновляем.

  • В конце возвращаем накопленный longest.

Код выглядит лаконичнее, чем у GPT, и даже более человечно что-ли. Есть комментарии, но минимальные. Замечу, что Grok сразу проверил граничные случаи, пустая строка или длины 1, возвращает как есть (что правильно). Основной цикл двойной, вложенные while, в худшем случае тоже дают сложность порядка O(n^2). Без дополнительных структур, так что по памяти эффективнее, чем DP.

Результат на тестах: также безупречно. Все строки Grok обработал верно. Он нашёл палиндромы той же длины, что и решение GPT. Например, на строке "racecarxyz" вернул "racecar", всё правильно.

Можно ли к чему-то придраться? Разве что отсутствует явная оптимизация преждевременного выхода, но её редко кто пишет. Код читабельный, простой и рабочий.

Вердикт: Grok тоже заслуживает 10/10 за решение. Можно спорить, чей подход лучше, DP или центр расширения, но обе реализации верны. По скорости примерно равны.

Решение от DeepSeek R1

Третьим на очередь был DeepSeek. Он решил задачу… практически тем же методом, что и Grok! Вот фрагмент ответа DeepSeek:

def longest_palindrome(s: str) -> str:

    res = ""

    for i in range(len(s)):

        # Палиндром нечётной длины

        l = r = i

        while l >= 0 and r < len(s) and s[l] == s[r]:

            if r - l + 1 > len(res):

                res = s[l:r+1]

            l -= 1

            r += 1

        # Палиндром чётной длины

        l, r = i, i+1

        while l >= 0 and r < len(s) and s[l] == s[r]:

            if r - l + 1 > len(res):

                res = s[l:r+1]

            l -= 1

            r += 1

    return res if res != "" else s

На первый взгляд почти клон решения Grok (и классического алгоритма). Различия минимальны, переменная результата называется res, и в конце DeepSeek возвращает s, если никакого палиндрома не нашлось (хотя на самом деле в худшем случае res останется пустой только если s пустая, так что это эквивалентно).

В целом, код верный. На всех тестах решение DeepSeek тоже отработало правильно. Однако, справедливости ради, отметим пару моментов:

  • DeepSeek не обработал явно случай пустой строки или длины 1. У него res изначально "", и если вход s пустой, то в конце он вернёт s (то есть ""). Это ок. А вот если строка из одного символа, цикл for пробежит, res станет равен этому символу, и всё тоже ок. То есть не упадёт нигде – тут порядок.

  • На больших строках решение рабочее, но может быть медленнее, чем DP у GPT, если строка очень длинная (сотни тысяч символов). Но такие экстремы мы не тестируем, а на разумных размерах всё нормально.

В общем, DeepSeek справился на 10/10 по корректности. Получается, три модели подряд выдали безупречный код. Но ведь должны же быть различия? Они есть, но тонкие: у DeepSeek чуть менее отполированный ответ. Например, он не добавил поясняющих комментариев про проверку центров. Код рабочий, но создаётся впечатление, что модель просто воспроизвела известный паттерн, почти не добавив от себя оптимизаций или пояснений. Впрочем, это скорее мои придирки.

Решение от Яндекс Алисы (YandexGPT)

Четвёртым номером у нас Алиса. Честно говоря, ожиданий особо не было. Воспользовались чатом с Алисой в текстовом режиме. Задали точно тот же запрос. Алиса подумала чуточку подольше предыдущих моделей. Она не выдала сразу код функции, как это сделали остальные. Вместо этого Алиса начала рассуждать о задаче: мол, чтобы найти самый длинный палиндром, можно проверить все подстроки, но это долго, лучше расширяться от центра, бла-бла. И только после этого кусок кода. Приводим существенную часть ответа Алисы:

Самый эффективный алгоритм для данной задачи – проверка палиндромов от центра строки. Нужно перебрать центры палиндрома (каждый символ и промежутки между символами) и расширяться влево и вправо, пока символы совпадают.

Вот пример реализации на Python:

def longest_palindrome(s: str) -> str:

    n = len(s)

    if n < 2:

        return s

    best = s[0]

    for center in range(n):

        # палиндром нечетной длины

        l = r = center

        while l >= 0 and r < n and s[l] == s[r]:

            if r - l + 1 > len(best):

                best = s[l:r+1]

            l -= 1

            r += 1

        # палиндром четной длины

        l = center

        r = center + 1

        while l >= 0 and r < n and s[l] == s[r]:

            if r - l + 1 > len(best):

                best = s[l:r+1]

            l -= 1

            r += 1

    return best

Как видим, в конечном итоге Алиса сгенерировала практически тот же алгоритм, что и Grok/DeepSeek. Различия минимальны: переменные названы чуть по-другому (best вместо longest), цикл for center in range(n) – аналог for i in range(len(s)). Код корректный и по структуре, и по логике.

В целом, Алиса справилась на 9/10.

Решение от GigaChat

Наконец, очередь GigaChat, нашей надежды конкурировать с OpenAI. GigaChat 2.0 доступен через веб-интерфейс Сбера. К немалому удивлению, GigaChat ответил очень похоже на GPT-5.1: сразу дал код и краткий комментарий. Видимо, сказываются корпоративные сценарии, GigaChat привык отвечать чётко по запросу. Приводим его решение:

def longest_palindrome(s: str) -> str:

    if not s:

        return ""

    longest = s[0]

    for i in range(len(s)):

        # Проверяем палиндром с центром в i (нечётная длина)

        l = r = i

        while l >= 0 and r < len(s) and s[l] == s[r]:

            if r - l + 1 > len(longest):

                longest = s[l:r+1]

            l -= 1

            r += 1

        # Проверяем палиндром чётной длины с центром между i и i+1

        l, r = i, i+1

        while l >= 0 and r < len(s) and s[l] == s[r]:

            if r - l + 1 > len(longest):

                longest = s[l:r+1]

            l -= 1

            r += 1

    return longest

На первый взгляд, код почти идентичен решениям Grok/DeepSeek/Алисы. Опять центр расширения, всё те же две формы цикла. Отличия лишь в синтаксических мелочах:

  • GigaChat первым делом проверяет if not s: return "" – то есть пустую строку обрабатывает (вместо if n < 2 или подобного у других).

  • Использует переменную longest для результата, аналогично Grok.

  • Комментарии добавил на русском, причём довольно понятные и в одном стиле с предыдущими решениями.

Честно говоря, тут уже сложно найти какие-то уникальные черты, все модели, кроме GPT (который выбрал DP), выдали по сути один и тот же алгоритм. Возможно, потому что это действительно оптимальное решение, и все его знают.

Тесты: GigaChat, как и остальные, успешно прошёл все проверки. Нигде не споткнулся. Казалось бы, 10/10, молодец.

Тем не менее, есть один момент, которым GigaChat выделился: он был немного многословнее в объяснениях до кода. Перед тем как показать функцию, модель написала (переводим с небольшим сокращением): «Для решения задачи будем использовать подход с расширением от центра. Это позволит получить решение за квадратичное время…» – и так далее, пару предложений. Затем шёл код. После кода GigaChat даже добавил: «Таким образом, функция longest_palindrome вернёт самый длинный палиндром.» То есть как бы подвёл итог.

Для статьи мы эти вступления опустили, приведя только код, но для оценки опыта отметим: GigaChat явно заточен под более формальную подачу. Возможно, это связано с тем, что его продвигают для корпоративных клиентов, где лишнее пояснение не помешает.

Оценка: 10/10 по качеству решения. Код правильный, оптимальный и понятный.

Сравнение результатов и выводы

Все пять нейросетей успешно решили задачу нахождения палиндрома. Если честно, мы рассчитывали что хоть кто-то ошибётся ан нет, ни одной ошибки в коде. Возможно, задача была слишком простая для топ-моделей 2025 года.

  • GPT-5.1 – ожидаемо лидер. Модель показала высокий класс: решила задачу оптимально, код документирован, ни одного сбоя. Более того, GPT проявил инициативу – выбрал метод DP, хотя можно было проще. Это говорит о глубоком понимании: модель знает несколько способов и выбирает подходящий. В реальных задачах GPT-5.1 будет, скорее всего, самым надёжным и универсальным помощником. Минусы? Разве что цена и ограничение доступа.

  • Grok (xAI) – приятно удивил. По чисто кодерским навыкам он ничем не уступил GPT. Код даже более лаконичный, что многим понравится.

  • DeepSeek – доказал, что open-source AI тоже может писать качественный код. Преимущество очевидно: модель открытая, её можно настроить под себя, дать свой контекст (документацию проекта, например) и ни от кого не зависеть.

  • Яндекс Алиса (YandexGPT) – оказывается, ваш голосовой помощник может помочь с кодом! Конечно, пока Алиса не профильный инструмент для разработчика. У неё нет своего IDE-плагина (в отличие от GigaChat), да и в облаке YandexGPT API ориентирован больше на обработку текста, чем кода. Впрочем, даже сейчас вы можете спросить у неё совета по алгоритму или синтаксису, и она ответит, как ChatGPT. Недостатки: чуть менее строгий стиль, да и неизвестно, насколько глубоко она знает тонкости языков.

  • Sber GigaChat – показал себя уверенным профессионалом. В коде полный порядок. Плюс GigaChat умеет работать с многими модальностями (картинки, звук), что выходит за рамки нашего теста, но для некоторых задач будет жирным плюсом.

Пользуйтесь на здоровье тем, что подходит под ваши задачи.

Комментарии (9)


  1. gmtd
    26.11.2025 09:58

    1. Блоки кода можно отформатировать

    2. Задал эту задачу Mistral Mini, которая бесплатна
      Получил тот же ответ с хорошими объяснениями и комментариями в коде
      Вы бы еще на сложении двух чисел современные модели тестировали.


    1. MVideohabr Автор
      26.11.2025 09:58

      Какой у Вас опыт? Чем и для каких задач пользуетесь? Галлюцинации не беспокоят?


    1. tbl
      26.11.2025 09:58

      Вместо того, чтобы взять стандартный набор тестов типа MBPP, по нему прогнать модельки и посчитать скоринг, сделать выводы, задали вопрос, на который любая большая моделька ответит, и пытаетесь только по нему оценить качество всей модельки. Да еще и в виде плохо оформленного текста


  1. Rustyd
    26.11.2025 09:58

    Интересно было бы взять какую-нибудь прям сложную задачу и выдать её представленным моделям, только актуальным версиям (тот же Гигачат недавно обновился). Плюс, добавить Гемини 3 и Квен (может ещё и Сонет).

    Но это так, личные хотелки.


    1. MVideohabr Автор
      26.11.2025 09:58

      Сложная задача, например?


      1. Rustyd
        26.11.2025 09:58

        Всегда интересно читать про задачи/цели, которые возникали в процессе какой-либо работы. Возможно что-то взять из личного опыта или опыта коллег.


  1. wintsa
    26.11.2025 09:58

    Явно какая-то опечатка. "abbaacaab" должен давать (и дает) "baacaab". Не понятно, что имелось в виду.


  1. HlebusheckCoder
    26.11.2025 09:58

    За что Алиса балл потеряла?


    1. MVideohabr Автор
      26.11.2025 09:58

      На самом деле, оценка и баллы весьма условны. Личное мнение. По сути: Алиса чуть дольше ссображала. Ну, и не выдала сразу код функции, как это сделали остальные. Вместо этогоначала рассуждать о задаче: мол, чтобы найти самый длинный палиндром, можно проверить все подстроки, но это долго, лучше расширяться от центра, бла-бла. И только после этого кусок кода.