Finde das seltsame Zeichen in einem Muster

20

Eingang

Die erste Zeile ist eine bestimmte Zeichenfolge, die beliebig oft wiederholt wird. Zum Beispiel könnte es sein abcabcabcabc, [];[];[];usw. Es kann abgeschnitten werden; zum Beispiel: 1231231231. Finden Sie immer die kürzeste Zeichenfolge. Wenn die Zeile beispielsweise ist 22222, dann ist die Zeichenfolge 2nicht 22oder 22222oder irgendetwas anderes. Die Saite wird immer mindestens 2 Mal wiederholt.

Alle folgenden Zeilen sind das Muster, das um eine beliebige Zahl versetzt ist. Zum Beispiel könnte es sein:

abcabcabc
cabcabcab
bcabcabca

(um 1 versetzt), oder es könnte sein:

abcdefabcdefabcdefabc
cdefabcdefabcdefabcde
efabcdefabcdefabcdefa

(Versetzt um 4).

Eines der Zeichen in der Eingabe ist falsch. (Es ist garantiert, dass es sich nicht in der ersten Zeile befindet.) Beispiel:

a=1a=1a=1
=1a=1a=1a
1a=11=1a=
a=1a=1a=1
=1a=1a=1a

die 1on line 3 ist die ungerade aus.

Ausgabe

Sie müssen die (nullbasierten, von links oben ausgehenden) Koordinaten der ungeraden ausgeben. Beispielsweise ist in der obigen Eingabe die entsprechende Ausgabe 4,2. Sie können auch ein oder sogar ein anderes Format ausgeben 4 2, sofern Sie wissen, wie die Ausgabe aussehen soll."4""2"[[4],[2]]

Testfälle

Eingang:

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

Ausgabe: 16,2

Eingang:

][[][][[][][[][][[][][[
[][][[][][[][][[][][[][
[][[][][[][][[][][[][][
[[][][[]]][[][][[][][[]

Ausgabe: 8,3

Eingang:

...
. .
...

Ausgabe: 1,1

Eingang:

ababa
babab
ababb
babab

Ausgabe: 4,2

Gehen!

Türknauf
quelle
Welche Zeichen können in der Zeichenfolge enthalten sein? Druckbares ASCII? ASCII? Unicode?
Dennis
@Dennis Nur druckbares ASCII (das kann grundsätzlich für jede Herausforderung mit Zeichenfolgen angenommen werden; andernfalls müssten wir das für fast jede Herausforderung angeben: P)
Türknauf
Das dachte ich mir. Ich denke über einen Ansatz nach, der ein unbenutztes Zeichen erfordern würde, also dachte ich, ich würde fragen.
Dennis
Sollen wir Groß- abc/cab/abcund Kleinschreibung wie folgt prüfen: - und 0 2hier ausgeben ?
user2846289
@VadimR Nein, da nur ein Zeichen falsch ist.
Türklinke

Antworten:

7

Bash Perl, 231 229 218 178 164 166 138 106 74 Bytes

/^(((.*).*)\2+)\3$/;$_.=$1x2;$.--,die$+[1]if/^(.*)(.)(.*)
.*\1(?!\2).\3/

Das Skript erfordert die Verwendung des -nSchalters, der zwei der Bytes ausmacht.

Die Idee, zwei Kopien aller vollständigen Wiederholungen des Musters anzuhängen, wurde aus der Antwort von MT0 übernommen .

Im Gegensatz zu allen anderen Antworten wird bei diesem Ansatz versucht, das Muster der aktuellen Eingabezeile in jeder Iteration zu extrahieren. Es schlägt in der Zeile mit dem ungeraden Zeichen fehl (und verwendet stattdessen das Muster der vorherigen Zeile). Dies geschieht, um die Musterextraktion in die Schleife aufzunehmen, die es schafft, einige Bytes zu sparen.

Ungolfed-Version

#!/usr/bin/perl -n

# The `-n' switch makes Perl execute the entire script once for each input line, just like
# wrapping `while(<>){…}' around the script would do.

/^(((.*).*)\2+)\3$/;

# This regular expression matches if `((.*).*)' - accessible via the backreference `\2' -
# is repeated at least once, followed by a single repetition of `\3" - zero or more of the
# leftmost characters of `\2' - followed by the end of line. This means `\1' will contain
# all full repetitions of the pattern. Even in the next loop, the contents of `\1' will be
# available in the variable `$1'.

$_.=$1x2;

# Append two copies of `$1' to the current line. For the line, containing the odd
# character, the regular expression will not have matched and the pattern of the previous
# line will get appended.
#
# Since the pattern is repeated at least two full times, the partial pattern repetition at
# the end of the previous line will be shorter than the string before it. This means that
# the entire line will the shorter than 1.5 times the full repetitions of the pattern, 
# making the two copies of the full repetitions of the pattern at least three times as 
# long as the input lines.

$.-- , die $+[1] if

# If the regular expression below matches, do the following:
#
#   1. Decrement the variable `$.', which contains the input line number.
#
#      This is done to obtain zero-based coordinates.
#
#   2. Print `$+[1]' - the position of the last character of the first subpattern of the
#      regular expression - plus some additional information to STDERR and exit.
#
#      Notably, `die' prints the (decremented) current line number.

/^(.*)(.)(.*)
.*\1(?!\2).\3/;

# `(.*)(.)(.*)', enclosed by `^' and a newline, divides the current input line into three
# parts, which will be accesible via the backreferences `\1' to `\3'. Note that `\2'
# contains a single character.
#
# `.*\1(?!\2).\3' matches the current input line, except for the single character between
# `\1' and `\3' which has to be different from that in `\2', at any position of the line
# containing the pattern repetitions. Since this line is at least thrice as long as
# `\1(?!\2).\3', it will be matched regardless of by how many characters the line has been
# rotated.

Beispiel

Für den Testfall

codegolfcodegolfco
egolfcodegolfcodeg
lfcodegolfcodegoff
odegolfcodegolfcod
golfcodegolfcodego
fcodegolfcodegolfc

Die Ausgabe der Golf-Version ist

16 at script.pl line 1, <> line 2.

was bedeutet, dass das ungerade Zeichen die Koordinaten hat 16,2.

Dieser offensichtliche Missbrauch macht sich das liberale Ausgabeformat zunutze.

Kurz vor dem Beenden sind die Inhalte einiger spezieller Perl-Variablen:

$_  = lfcodegolfcodegoff\ncodegolfcodegolfcodegolfcodegolf
$1  = lfcodegolfcodego
$2  = f
$3  = f

( $nEnthält die Übereinstimmung des Submusters, auf das über die Rückreferenz zugegriffen werden kann \n.)

Dennis
quelle
Cleveres Fangen des Antwortgerätes. Es kann durch ein Byte optimiert werden:^((.*?)(.*?))(?=\1+\2$)
Heiko Oberdiek
Ich wechselte zu der Sprache, die die populären Kinder benutzen. Kann wahrscheinlich weiter abgespielt werden; Dies ist mein erstes Perl-Skript seit über einem Jahrzehnt ...
Dennis
2
... und du bist über ein Jahrzehnt zu spät, wenn du denkst, dass Perl das ist, was die beliebten Kinder verwenden
zwar am
Diese Antwort bekommt nicht die Liebe, die sie verdient. sieht für mich aus wie der Gewinner @Doorknob
Ardnew
8

Perl, 212 191 181 168 Bytes

$_=<>;/^(((.*?)(.*?))\2+)\3$/;$x=$1x4;while(<>){chop;$x=~/\Q$_\E/&&next;for$i(0..y///c-1){for$r(split//,$x){$b=$_;$b=~s/(.{$i})./$1$r/;$x=~/\Q$b\E/&&die$i,$",$.-1,$/}}}
  • Diese Version benutzt einen optimierten Trick, um die Antworteinheit zu fangen, der in Dennis ' Antwort gelernt wurde .
  • Optimierung durch Verwendung der Eigenschaft, dass alle Linien die gleiche Länge haben.
  • Das Zeilenende wird auch für die letzte Zeile benötigt, andernfalls sollte chompstatt chopverwendet werden.
  • Optimierungen des Kommentars von ardnew hinzugefügt.

Alte Version, 212 Bytes:

$_=<>;chop;/^(.+?)\1+(??{".{0,".(-1+length$1).'}'})$/;$;=$1;while(<>){$x=$;x length;chop;$x=~/\Q$_\E/&&next;for$i(0..-1+length$_){for$r(split//,$;){$b=$_;$b=~s/(.{$i})./$1$r/;$x=~/\Q$b\E/&&exit print$i,$",$.-1}}}

Ungolfed-Version:

$_ = <>;  # read first line
/^(((.*?)(.*?))\2+)\3$/;
# The repeat unit \2 consists of \3 and \4,
# and the start part \2 can be added at the end (as partial or even full unit).
$x = $1 x 4; # $x is long enough to cover each following line

# Old version:
# /^(.+?)\1+(??{ ".{0," . (-1 + length $1) . '}' })$/;
# $a = $1; # $a is the repeat unit.
# The unit is caught by a non-greedy pattern (.+?) that is
# repeated at least once: \1+
# The remaining characters must be less than the unit length.
# The unit length is known at run-time, therefore a "postponed"
# regular expression is used for the remainder.

# process the following lines until the error is found
while (<>) {
    # old version:
    # $x = $a x length;
    # $x contains the repeated string unit, by at least one unit longer
    # than the string in the current line
    chop; # remove line end of current line
    $x =~ /\Q$_\E/ && next;
          # go to next line, if current string is a substring of the repeated units;
          # \Q...\E prevents the interpretation of special characters
    # now each string position $x is checked, if it contains the wrong character:
    for $i (0 .. y///c - 1) {  # y///c yields the length of $_
        for $r (split //, $x) { #/ (old version uses $a)
            # replace the character at position $i with a
            # character from the repeat unit
            $b = $_;
            $b =~ s/(.{$i})./$1$r/;
            $x =~ /\Q$b\E/
               && die $i, $", $. - 1, $/;
               # $" sets a space and the newline is added by $/;
               # the newline prevents "die" from outputting line numbers
        }
    }
}
Heiko Oberdiek
quelle
Tolle Lösung und Kommentare, ich muss mehr Regex lernen;)
Newbrict
1
Der erste chopist unnötig - sollte entfernt werden. die endgültige exit printersetzt werden kann die(add ,$/das Extramaterial zu verstecken (falls erforderlich)). auch length$_kann ersetzt werden mity///c
ardnew
@ardnew: Vielen Dank, ich habe den ersten entfernt chop, da $vor dem Zeilenumbruch am Ende der Zeichenfolge passt. Das Verstecken des zusätzlichen dieMaterials über die hinzugefügte Newline scheint mir notwendig zu sein. Auch y///cist viel kürzer als length$_und ein Byte kürzer als lengthohne das Unnötige $_.
Heiko Oberdiek
1
@ardnew: Ich hatte die Ausführlichkeit des Würfels vergessen . Es enthält sogar die Zeilennummer! Ich werde das in meinem nächsten Update verwenden.
Dennis
3

C 187 Bytes

Einschränkungen.

  • Verwenden Sie keine Eingabezeichenfolgen, die länger als 98 Zeichen sind :)

Golf Version

char s[99],z[99],*k,p,i,I,o,a;c(){for(i=0;k[i]==s[(i+o)%p];i++);return k[i];}main(){for(gets(k=s);c(p++););for(;!(o=o>p&&printf("%d,%d\n",I,a))&&gets(k=z);a++)while(o++<p&&c())I=I<i?i:I;}

Ungolfed-Version

char s[99],z[99],*k,p,i,I,o,a;

c()
{
    for(i=0
       ;k[i]==s[(i+o)%p]
       ;i++)
       ;
    return k[i];
}

main()
{
    for(gets(k=s);c(p++);)
         ;
    for(;!(o=o>p&&printf("%d,%d\n",I,a)) && gets(k=z);a++)
           while(o++ < p && c())
            I=I<i?i:I;
}
asr
quelle
2

Python 303, 292

r=raw_input
R=range
s=r()
l=len(s)
m=1
g=s[:[all((lambda x:x[1:]==x[:-1])(s[n::k])for n in R(k))for k in R(1,l)].index(True)+1]*l*2
while 1:
 t=r()
 z=[map(lambda p:p[0]==p[1],zip(t,g[n:l+n]))for n in R(l)]
 any(all(y)for y in z)or exit("%d,%d"%(max(map(lambda b:b.index(False),z)),m))
 m+=1

Die Eingabe erfolgt über stdin. Ich werde es erklären, wenn es irgendeine Nachfrage gibt, aber es sieht nicht so aus, als würde ich trotzdem gewinnen.

Fraxtil
quelle
1

Perl, 157, 154

Edit : -3 dank ardnew 'Vorschlag.

<>=~/^(((.*?).*?)\2+)\3$/;$p=$2;$n=$+[1];while(<>){s/.{$n}/$&$&/;/(\Q$p\E)+/g;$s=$p;1while/./g*$s=~/\G\Q$&/g;print$n>--($m=pos)?$m:$m-$n,$",$.-1,$/if pos}

Ich brauchte einige Zeit (ein und aus, natürlich nicht 5 Tage ;-)) und die Idee zum Algorithmus war anfangs schwer zu fassen (obwohl ich das Gefühl hatte, dass er da war), aber schließlich (und plötzlich) wurde alles klar.

Wenn die Länge der Zeichenfolge ein Vielfaches der Länge des Musters ist und die Zeichenfolge nicht mit dem Anfang des Musters beginnt, wird durch Verketten der Zeichenfolge mit sich selbst ein Muster anstelle der Verkettung erzeugt (stellen Sie sich vor, Sie wiederholen ein Wort auf dem kreisförmigen Menüband endlos) Schweißen ist nicht wichtig). Daher besteht die Idee darin, die Linie auf mehrere Längeneinheiten zu kürzen und das Original damit zu verknüpfen. Das Ergebnis wird garantiert mindestens einmal mit dem Muster übereinstimmen, selbst wenn die Zeichenfolge das falsche Zeichen enthält. Von da an ist es leicht, die Position des beleidigenden Charakters zu finden.

Erste Zeile ist schamlos von Heiko Oberdieks Antwort entlehnt :-)

<>=~/^(((.*?).*?)\2+)\3$/;      # Read first line, find the repeating unit
$p=$2;                          # and length of whole number of units.
$n=$+[1];                       # Store as $p and $n.
while(<>){                      # Repeat for each line.
    s/.{$n}/$&$&/;              # Extract first $n chars and
                                # append original line to them.
    /(\Q$p\E)+/g;               # Match until failure (not necessarily from the
                                # beginning - doesn't matter).
    $s=$p;                      # This is just to reset global match position
                                # for $s (which is $p) - we could do without $s,
                                # $p.=''; but it's one char longer.
                                # From here, whole pattern doesn't match -
    1while/./g*$s=~/\G\Q$&/g;   # check by single char.
                                # Extract next char (if possible), match to 
                                # appropriate position in a pattern (position 
                                # maintained by \G assertion and g modifier).
                                # We either exhaust the string (then pos is 
                                # undefined and this was not the string we're
                                # looking for) or find offending char position.

    print$n>--($m=pos)?$m:$m-$n,$",$.-1,$/if pos
}
user2846289
quelle
1
gute Arbeit. Ich denke, Sie können ersetzen /.{$n}/;$_=$&.$_;durchs/.{$n}/$&$&/;
ardnew
1

JavaScript (ES6) - 147 133 136 Zeichen

s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Erwartet, dass die zu testende Zeichenfolge in der Variablen enthalten ist, sund gibt das Ergebnis an die Konsole aus.

var repetitionRE = /^(((.*).*)\2+)\3\n/;
                                        // Regular expression to find repeating sequence
                                        // without any trailing sub-string of the sequence.
var sequence = repetitionRE.exec(s)[1]; // Find the sequence string.
s.split('\n')                           // Split the input into an array.
 .map(
   ( row, index ) =>                    // Anonymous function using ES6 arrow syntax
   {
     var testStr = row + '᛫'+ sequence + sequence;
                                        // Concatenate the current row, a character which won't
                                        // appear in the input and two copies of the repetitions
                                        // of the sequence from the first line.
     var match = /^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(testStr);
                                        // Left of the ᛫ finds sub-matches for a single
                                        // character and the sub-strings before and after.
                                        // Right of the ᛫ looks for any number of characters
                                        // then the before and after sub-matches with a
                                        // different character between.
      if ( match )
       console.log( match[1].length, index );
                                        // Output the index of the non-matching character
                                        // and the row.
   }         
 );

Testfall 1

s="codegolfcodegolfco\negolfcodegolfcodeg\nlfcodegolfcodegoff\nodegolfcodegolfcod\ngolfcodegolfcodego\nfcodegolfcodegolfc"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Ausgänge

16 2

Testfall 2

s="][[][][[][][[][][[][][[\n[][][[][][[][][[][][[][\n[][[][][[][][[][][[][][\n[[][][[]]][[][][[][][[]"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Ausgänge

8 3

Testfall 3

s="...\n. .\n..."
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Ausgänge

1 1

Testfall 4

s="ababa\nbabab\nababb\nbabab"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Ausgänge

4 2

Testfall 5

s="xyxy\nyyxy"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Ausgänge

0 1

Testfall 6

s="ababaababa\nababaaaaba"
s.split('\n').map((x,i)=>(v=/^(.*)(.)(.*)᛫.*\1(?!\2).\3/.exec(x+'᛫'+(a=/^(((.*).*)\2+)\3\n/.exec(s)[1])+a))&&console.log(v[1].length,i))

Ausgänge

6 1
MT0
quelle
Leider scheitert dieser Ansatz, wenn z s="xyxy\nyyxy". Für die zweite Zeile match[4]wird sein yy; es sollte einfach sein y.
Dennis
Überarbeitet und um 14 Zeichen gekürzt.
MT0
Sehr schön! Ich hatte irgendwann den gleichen zweiten regulären Ausdruck probiert, aber ich habe das minimale Muster zweimal anstelle des maximalen Musters angehängt (und bin daher miserabel gescheitert). Ein kleines Problem: Der erste reguläre ababAusdruck zeigt das Muster von ababaababa; Sie müssen verwenden ^…$.
Dennis
/^…\n/funktioniert oder/^…$/m
MT0
1
Der führende Code wird möglicherweise nicht benötigt ^(zumindest nicht für einen der 6 aufgelisteten Testfälle - aber es gibt wahrscheinlich ein Gegenbeispiel, in dem dies der Fall ist, in dem ich es belassen habe).
MT0