Längste umgekehrte palindromische DNA-Teilzeichenfolge

11

Wie Sie vielleicht wissen, gibt es in der DNA vier Basen - Adenin ( A), Cytosin ( C), Guanin ( G) und Thymin ( T). Typischerweise Abindet Tund Cbindet mit Gund bildet die "Sprossen" der DNA-Doppelhelixstruktur .

Wir definieren das Komplement einer Basis als die Basis, an die sie bindet - dh das Komplement von Ais T, das Komplement von Tis A, das Komplement von Cis Gund das Komplement von Gis C. Wir können das Komplement eines DNA-Strings auch als den String definieren, bei dem jede Base komplementiert ist, z. B. das Komplement von GATATCis CTATAG.

Aufgrund der doppelsträngigen Struktur der DNA sind die Basen auf einem Strang komplementär zu den Basen auf dem anderen Strang. DNA hat jedoch eine Richtung und die DNA-Transkription erfolgt in entgegengesetzten Richtungen auf den beiden Strängen. Daher interessieren sich Molekularbiologen häufig für das umgekehrte Komplement eines DNA-Strings - im wahrsten Sinne des Wortes das Gegenteil des Komplements des Strings.

Um unser vorheriges Beispiel zu erweitern, ist das umgekehrte Komplement von GATATCalso CTATAGrückwärts GATATC. Wie Sie vielleicht bemerkt haben, entspricht in diesem Beispiel das umgekehrte Komplement der ursprünglichen Zeichenfolge - wir nennen eine solche Zeichenfolge ein umgekehrtes Palindrom . *

Können Sie bei einer DNA-Kette den längsten Teilstring finden, der ein umgekehrtes Palindrom ist?

* Ich verwende den Begriff "umgekehrtes Palindrom" aus Rosalind , um mich von der üblichen Bedeutung des Palindroms zu unterscheiden.


Eingang

Die Eingabe ist eine einzelne Zeichenfolge, die nur aus den Zeichen ACGTin Großbuchstaben besteht. Sie können entweder eine Funktion oder ein vollständiges Programm für diese Herausforderung schreiben.

Ausgabe

Sie können die Ausgabe entweder über Drucken oder Zurückgeben wählen (letztere Option ist nur bei einer Funktion verfügbar).

Ihr Programm sollte den längsten umgekehrten palindromischen Teilstring der Eingabezeichenfolge ausgeben, wenn es eine eindeutige Lösung gibt. Wenn mehrere Lösungen vorhanden sind, können Sie entweder eine einzelne oder alle (nach Ihrer Wahl) ausgeben. Duplikate sind in Ordnung, wenn Sie alle ausgeben möchten.

Der Eingang hat garantiert eine Lösung von mindestens Länge 2.

Gearbeitetes Beispiel

ATGGATCCG -> GGATCC

Das umgekehrte Komplement von GGATCCist selbst ( GGATCC --complement--> CCTAGG --reverse--> GGATCC), ebenso GGATCCwie ein umgekehrtes Palindrom. GATCist auch ein umgekehrter Palindom, aber es ist nicht der längste.

Testfälle

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

Wertung

Dies ist Code Golf, daher gewinnt die Lösung in den wenigsten Bytes.

Sp3000
quelle
Es wäre schöner gewesen, wenn das Drucken von allen einen Bonus gehabt hätte.
Optimierer
@Optimizer ist das Drucken nicht nur am längsten schwieriger als das Drucken aller?
Trichoplax
Oder meinst du damit, die längsten zu drucken?
Trichoplax
@githubphagocyte ja, dein zweiter Kommentar.
Optimierer

Antworten:

6

Pyth, 37 36 28 24 Bytes

ef&}TzqmaCd6T_mx4aCk6Tyz

Dies ist eine super kurze Version, die die Tipps von FryAmTheEggman und den umgekehrten Palindrom-Check-Trick von Peter kombiniert.

Dies funktioniert jedoch nur mit Pyth 3.0.1, das Sie über diesen Link herunterladen und wie folgt ausführen können

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

(Nur Linux Bash. Drücken Sie unter Windows die Eingabetaste anstelle von <<< und geben Sie die Eingabe ein.)


Dies ist meine vorherige Einreichung - 28-Byte-Lösung

J"ACGT"ef&}TzqTjk_m@_JxJdTyz

Vielen Dank an FryAmTheEggman für diese Version. Dieser erstellt alle möglichen Teilmengen der Eingabe-DNA-Zeichenfolge, filtert die Teilmengen unter der Bedingung, dass die Teilmenge eine Teilzeichenfolge der Eingabe ist und die Umkehrung der Transformation gleich der Teilmenge selbst ist.

Aufgrund aller möglichen Teilmengenerstellung nimmt dies noch mehr Speicherplatz in Anspruch als Peters Antwort.


Dies ist meine erste Einreichung - 36-Byte-Lösung.

J"ACGT"eolNfqTjk_m@_JxJdTm:zhkek^Uz2

Dies ist die genaue Übersetzung meiner CJam-Antwort . Ich hatte gehofft, dass dies viel kleiner sein würde, aber es stellte sich heraus, dass die fehlende Übersetzungsmethode die Größe fast gleich machte (obwohl immer noch 2 Bytes kleiner).

Probieren Sie es hier online aus

Optimierer
quelle
Uzist äquivalent zu Ulz.
isaacg
1
J"ACGT"eolNf&}TzqTjk_m@_JxJdTyzDie Verwendung yfür Teilmengen und das anschließende Herausfiltern von Zeichenfolgen, die keine Teilzeichenfolgen sind, zist kürzer :)
FryAmTheEggman
1
Oh, und wenn Sie das tun, müssen Sie nicht sortieren, da yes bereits nach Länge sortiert ist. Sie können einfach tunef...
FryAmTheEggman
5

GolfScript ( 35 34 Bytes)

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

Zu Testzwecken möchten Sie möglicherweise verwenden

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

Dies fügt ein hinzu .&, um den doppelten Aufwand zu reduzieren.

Präparation

]{         # 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
}?
Peter Taylor
quelle
q{]{__(;\);}%~}h]{:c:i6f&_4f^W%=}=in CJam. Gleiche Größe. Versuchen Sie es nicht im Online-Compiler für etwas, das größer als 7 Längeneingaben ist
Optimizer
4

CJam, 39 38 Bytes

Ich bin sicher, dass dies weiter Golf gespielt werden kann ...

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

Nimmt den DNA-String von STDIN und gibt die längste reverse palindromische DNA an STDOUT aus

Probieren Sie es hier online aus

(Erklärung bald) (1 Byte dank Peter gespeichert)

Optimierer
quelle
4

Python 3, 125 Zeichen

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))

Schau ma, keine Indizierung! (Nun, außer um die Zeichenfolge umzukehren, zählt das nicht.)

Iterieren über die Unterketten wird durch Ausziehen Zeichen von der Vorderseite und am Ende durchgeführt unter Verwendung Stern Zuordnung . Die äußere Schleife entfernt Zeichen für den Anfang Sund sschleift für jedes solche Suffix alle Präfixe davon und testet sie nacheinander.

Das Testen auf das umgekehrte Palindrom erfolgt durch den Code

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

Hiermit wird überprüft, ob jedes Symbol und sein Gegenstück mit umgekehrter Zeichenfolge "AT", "TA", "CG" und "GC" sind. Ich fand auch, dass eine satzbasierte Lösung ein Zeichen kürzer ist, aber zwei Zeichen verliert, wenn bei Verwendung äußere Parens benötigt werden.

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

Dies fühlt sich immer noch so an, als könnte es verkürzt werden.

Schließlich wird das längste Palindrom gedruckt.

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

Ich hoffe, durch Leerzeichen getrennte Ausgänge sind in Ordnung. Wenn eine Liste auch in Ordnung ist, könnte der Stern entfernt werden. Ich hatte stattdessen versucht, das laufende Maximum in der Schleife zu verfolgen und die inneren Schleifen in ein Listenverständnis zu packen, damit ich das Maximum direkt ohne Konstruktion nehmen konnte l, und beide fielen etwas länger aus. Aber es war nah genug, dass es schwer zu sagen ist, welcher Ansatz tatsächlich der beste ist.

xnor
quelle
Ich wollte mit dieser Frage flexibler sein, deshalb habe ich kein genaues Ausgabeformat für gebundene Lösungen angegeben. Wenn klar ist, was die Lösungen sind, ist es in Ordnung, also ist eine Liste in Ordnung.
Sp3000
3

J (45)

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

Dies ist eine Funktion, die eine Zeichenfolge akzeptiert:

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

Erläuterung:

{.@(\:#&.>)@,@(('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   
Marinus
quelle
3

Perl - 59 Bytes

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

Wenn man den Shebang als eins zählt, wird die Eingabe von übernommen STDIN.

Beispielnutzung:

$ echo CTCGCGTTTGCATAACCGTACGGGCGGAACAGTCGGCGGTGCCTCCCAGG | perl dna.pl
CCGTACGG
primo
quelle
3

Python 2 - 177 Bytes

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)

Einfache rohe Gewalt. Der eigentliche "Reverse Palindromic" Check ist der einzig interessante Teil. Hier steht es besser lesbar:

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

Ich mache das auf jedem möglichen Teilstring und füge sie in eine Liste ein, wenn es wahr ist. Wenn es falsch ist, gebe ich stattdessen eine leere Zeichenfolge ein. Wenn alle Prüfungen abgeschlossen sind, gebe ich das längste Element der Liste aus. Ich habe eine leere Zeichenfolge verwendet, weil sie Bytes spart, weil nichts eingegeben wird, aber es bedeutet auch, dass das Programm nicht erstickt, wenn es keine Lösung gibt. Es gibt eine leere Zeile aus und wird ordnungsgemäß beendet.

U-Bahn
quelle
1
Dies scheint kürzer zu sein, wenn Sie alles unverständlich in einer einzigen Liste zusammenfassen. Ich musste die Logik ein wenig ändern, aber ich bekam 162 mit 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). Verwenden findSie auch für Zeichenfolgen über index:)
FryAmTheEggman