Самая длинная обратная палиндромная ДНК-подстрока


11

Как вы, наверное, знаете, в ДНК есть четыре основания - аденин ( A), цитозин ( C), гуанин ( G) и тимин ( T). Обычно Aсвязывается Tи Cсвязывается G, образуя «ступеньки» структуры двойной спирали ДНК .

Мы определяем дополнение базы как базу, с которой она связана - то есть дополнение Aесть T, дополнение Tесть A, дополнение Cесть Gи дополнение Gесть C. Мы также можем определить комплемент ДНК-строки как строку с каждым дополненным основанием, например, комплемент GATATCis CTATAG.

Из-за двухцепочечной структуры ДНК основания на одной цепи дополняют основания на другой цепи. Однако ДНК имеет направление, и транскрипция ДНК происходит в противоположных направлениях на двух нитях. Следовательно, молекулярные биологи часто заинтересованы в обратном дополнении цепочки ДНК - в буквальном смысле обратном дополнению цепочки.

Для того, чтобы расширить наш предыдущий пример, обратное дополнением GATATCявляется в CTATAGобратном направлении, так GATATC. Как вы могли заметить, в этом примере обратное дополнение равно исходной строке - такую ​​строку мы называем обратным палиндромом . *

Учитывая последовательность ДНК, можете ли вы найти самую длинную подстроку, которая является обратным палиндромом?

* Я использую термин «обратный палиндром», взятый из Розалинд , чтобы отличить его от обычного значения палиндрома.


вход

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

Выход

Вы можете выбрать вывод через печать или возврат (последний вариант доступен только в случае функции).

Ваша программа должна вывести самую длинную обратную палиндромную подстроку входной строки, если существует уникальное решение. Если существует несколько решений, вы можете либо вывести одно из них, либо все (по вашему выбору). Дубликаты в порядке, если вы решите вывести их все.

На входе гарантированно найдется решение как минимум длиной 2.

Работал пример

ATGGATCCG -> GGATCC

Обратным дополнением GGATCCявляется сама себе ( GGATCC --complement--> CCTAGG --reverse--> GGATCC), так GGATCCже как и обратный палиндром. GATCтакже является обратным палиндомом, но он не самый длинный.

Контрольные примеры

AT -> AT
CGT -> CG
AGCA -> GC
GATTACA -> AT, TA
ATGGATCCG -> GGATCC
CCCCCGGGGG -> CCCCCGGGGG
ACATATATAGACT -> ATATAT, TATATA
ATTCGATCTATGTAAAGAGG -> TCGA, GATC
CGCACGTCTACGTACCTACGTAG -> CTACGTAG
TCAATGCATGCGGGTCTATATGCAT -> ATGCAT, GCATGC [, ATGCAT]
CGCTGAACTTTGCCCGTTGGTAGAACGGACTGATGTGAACGAGTGACCCG -> CG, GC, TA, AT [, GC, CG, CG, CG, CG]
CTCGCGTTTGCATAACCGTACGGGCGGAACAGTCGGCGGTGCCTCCCAGG -> CCGTACGG

счет

Это код гольф, поэтому решение в наименьшем количестве байтов выигрывает.


Было бы лучше, если бы у каждого из них был какой-то бонус.
Оптимизатор

@ Оптимизатор не печатает только самый длинный и более сложный, чем печатать их все?
Трихоплакс

Или вы имеете в виду печать всех самых длинных?
Трихоплакс

@githubphagocyte да, твой второй комментарий.
Оптимизатор

Ответы:


6

Pyth, 37 36 28 24 байта

ef&}TzqmaCd6T_mx4aCk6Tyz

Сочетая советы от FryAmTheEggman и трюк с обратным палиндромом от Питера, это супер короткая версия.

Однако это работает только с Pyth 3.0.1, который вы можете скачать по этой ссылке и запустить как

python3 pyth.py -c "ef&}TzqmaCd6T_mx4aCk6Tyz" <<< "ATTCGATCTATGTAAAGAGG"

(только для linux bash. В Windows нажмите Enter вместо <<<, а затем введите ввод)


Это мое предыдущее представление - решение 28 байт

J"ACGT"ef&}TzqTjk_m@_JxJdTyz

Спасибо FryAmTheEggman за эту версию. Он создает все возможные подмножества входной строки ДНК, фильтрует подмножества при условии, что подмножество является подстрокой ввода, а обратное преобразование равно самому подмножеству.

Из-за всевозможного создания подмножества это занимает даже больше памяти, чем ответ Питера.


Это мое первое представление - 36-байтовое решение.

J"ACGT"eolNfqTjk_m@_JxJdTm:zhkek^Uz2

Это точный перевод моего ответа CJam . Я надеялся, что это будет намного меньше, но оказывается, что отсутствие метода перевода сделало его почти одинаковым по размеру (хотя на 2 байта меньше)

Попробуйте онлайн здесь


Uzэквивалентно Ulz.
Исаак

1
J"ACGT"eolNf&}TzqTjk_m@_JxJdTyzИспользование yдля подмножеств и последующая фильтрация строк, которые не являются подстрока, zкороче :)
FryAmTheEggman

1
Да, и если вы это сделаете, вам не нужно сортировать, потому что yуже отсортированы по длине. Вы можете просто сделатьef...
FryAmTheEggman

5

GolfScript ( 35 34 байта)

]{{..(;\);}%)}do{{6&}%.{4^}%-1%=}?

Для целей тестирования вы можете использовать

]{{..(;\);}%.&)}do{{6&}%.{4^}%-1%=}?

который добавляет, .&чтобы уменьшить дублированное усилие.

рассечение

]{         # Gather string into an array and do-while...
  {        #   Map over each string in the array
    ..     #     Make a couple of copies of the string
    (;     #     Remove the first character from one of them
    \);    #     Remove the last character from the other
  }%
  )        #   Extract the last string from the array
}do        # Loop until that last string is ''
           # Because of the duplication we now have an array containing every substring
           # of the original string, and if we filter to the first occurrence of each
           # string then they're in descending order of length
{          # Find the first element in the string satisfying the condition...
  {6&}%    #   Map each character in the string to its bitwise & with 6
  .{4^}%   #   Duplicate, and map each to its bitwise ^ with 4
           #   This serves to test for A <-> T, C <-> G
  -1%=     #   Reverse and test for equality
}?

q{]{__(;\);}%~}h]{:c:i6f&_4f^W%=}=в CJam. Тот же размер. Не пытайтесь использовать его в онлайн-компиляторе для чего-то большего, чем длина ввода 7
Optimizer

4

CJam, 39 38 байт

Я уверен, что это может быть дальше в гольфе ...

q:Q,,_m*{~Q<>}%{,~}${_"ACGT"_W%erW%=}=

Извлекает строку ДНК из STDIN и выводит самую длинную обратную палиндромную ДНК в STDOUT

Попробуйте онлайн здесь

(Объяснение в ближайшее время) (Сохранено 1 байт благодаря Питеру)


4

Python 3, 125 символов

S=input()
l=[]
while S:
 s=_,*S=S
 while s:l+=[s]*all(x+y in"ATA CGC"for x,y in zip(s,s[::-1]));*s,_=s
print(*max(l,key=len))

Смотри, мама, нет индексации! (Ну, кроме как перевернуть строку, это не считается.)

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

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

all(x+y in"ATA CGC"for x,y in zip(s,s[::-1]))

который проверяет, что каждый символ и его обратная строка имеют одно из следующих значений: «AT», «TA», «CG» и «GC». Я также обнаружил, что основанное на множестве решение на один символ короче, но теряет два символа при необходимости использования внешних паренсов при использовании.

set(zip(s,s[::-1]))<=set(zip("ACTG","TGAC"))

Это все еще чувствует, что это может быть сокращено.

Наконец, самый длинный палиндром напечатан.

print(*max(l,key=len))

Я надеюсь, что разделенные пробелами выходы в порядке. Если список также хорошо, звезда может быть удалена. Вместо этого я попытался отследить рабочий максимум в цикле, а также встроить внутренние циклы в понимание списка, чтобы я мог взять максимум напрямую, не создавая l, и оба оказались немного длиннее. Но это было достаточно близко, так что трудно сказать, какой подход на самом деле лучше.


Я хотел быть более гибким с этим вопросом, поэтому я не указал точный формат вывода для связанных решений. Если понятно, какие есть решения, тогда все в порядке, так что список в порядке.
Sp3000

3

J (45)

{.@(\:#&.>)@,@(('ACGT'&(|.@]-:[{~3-i.)#<)\\.)

Это функция, которая принимает строку:

   {.@(\:#&.>)@,@(('ACGT'&(|.@]-:[{~3-i.)#<)\\.) 'ATGGATCCG'
┌──────┐
│GGATCC│
└──────┘

Объяснение:

{.@(\:#&.>)@,@(('ACGT'&(|.@]-:[{~3-i.)#<)\\.) 

              (                          \\.)  for each prefix of each suffix
               (                      #<)      include the argument if,
                        |.@]                      its reverse
                            -:                    is equal to
                'ACGT'&(      [{~3-i.)            the complement
            ,@                                 ravel
   (\:#&.>)@                                   sort by length of item
{.@                                            take the first one   

3

Perl - 59 байт

#!perl -p
$_=$_[~!map$_[length]=$_,/((.)(?R)?(??{'$Q5'^$+.-$+}))/gi]

Считая Шебанг как единое, берется информация от STDIN.

Пример использования:

$ echo CTCGCGTTTGCATAACCGTACGGGCGGAACAGTCGGCGGTGCCTCCCAGG | perl dna.pl
CCGTACGG

3

Python 2 - 177 байт

s=raw_input()
r,l,o=range,len(s),[]
for a in[s[i:j+1]for i in r(l)for j in r(i,l)]:q=['TC GA'.index(c)-2for c in a];o+=[a if[-n for n in q][::-1]==q else'']
print max(o,key=len)

Простая грубая сила. Фактическая проверка «обратный палиндромик» - единственная интересная часть. Здесь написано более наглядно:

check = ['TC GA'.index(c)-2 for c in substring]
if [-n for n in check][::-1] == check:
    # substring is reverse palindromic

Я делаю это на каждой возможной подстроке и помещаю их в список, если это правда. Если это ложно, я вставляю пустую строку. Когда все проверки выполнены, я выводю самый длинный элемент списка. Я использовал пустую строку, потому что она экономит байты, не помещая ничего, но это также означает, что программа не захлебнется, если нет решения. Он выводит пустую строку и выходит изящно.


1
Это кажется короче, если вы смоете все в единый список непонимания. Мне пришлось немного изменить логику, но я получил 162 с s=raw_input();r,l,g=range,len(s),'TGCA';print max([a for a in[s[i:j+1]for i in r(l)for j in r(i,l)]if[g[n]for n in[~g.find(c)for c in a]]==list(a)[::-1]],key=len). Кроме того, для строк используйте findболее index:)
FryAmTheEggman
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.