Dopasowany ciąg znaków FizzBuzz

25

Powiedz, że masz taki ciąg:

abaabbbbbaabba

Policz, ile razy określony znak pojawia się w ciągu wejściowym, ale tylko wtedy, gdy znak pojawia się tylko raz z rzędu . Na przykład, jeśli postać jest a,

abaabbbbbaabba
^ x      x   ^

Łącznie byłoby 2 ( aanie liczą się, ponieważ apojawia się dwa razy z rzędu).

Jak to się ma do FizzBuzz?

Jeśli znak pojawia się 3 (lub wielokrotność 3) razy z rzędu lub 5 (lub wielokrotność 5) razy z rzędu, licznik jest zamiast tego zmniejszany . Jeśli jest to wielokrotność 3 i 5 razy, licznik jest nadal zwiększany. Pamiętaj, że licznik jest również zwiększany, jeśli postać pojawia się tylko raz z rzędu, i jest ignorowana, jeśli postać pojawia się dowolną liczbę razy z rzędu (oprócz sytuacji opisanych powyżej).

Reasumując, jeśli ciąg jest do meczu a,

input            counter (explanation)

a                 1 (single occurence)
aaa               -1(multiple of 3)
aaaaa             -1(multiple of 5)  
aaaaaaaaaaaaaaa   1 (multiple of 15)
aa                0 (none of the above)

aba               2 (two single instances)
aaba              1 (one single occurence(+1) and one double occurence(ignored))
aaaba             0 (one single occurence(+1) and one triple (-1)
aaaaaa            -1 (six is a multiple of three)

Implementacja referencyjna (nie golfowa) w java:

import java.util.Scanner;
import java.util.regex.*;

public class StrMatcher {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in); //Scanner to get user input
        int total = 0;//Running total of matches

        System.out.println("Enter a string: ");
        String strBeingSearched = sc.nextLine(); //String that will be searched

        System.out.println("Enter string to match with: ");
        String strBeingMatched = sc.nextLine(); //Substring used for searching

        //Simple regex matcher
        Pattern pattern = Pattern.compile("(" + strBeingMatched + ")+");
        Matcher matcher = pattern.matcher(strBeingSearched);

        while(matcher.find()){  //While there are still matches

            int length = matcher.end() - matcher.start();
            int numberOfTimes = length/strBeingMatched.length();//Calculate how many times in a row the string is matched

            if((numberOfTimes == 1)||((numberOfTimes % 3 == 0) && (numberOfTimes % 5 == 0))){
                total++; //Increment counter if single match or divisible by 15
            } else if((numberOfTimes % 3 == 0)||(numberOfTimes % 5 == 0)) {
                total--; //Decrement counter if divisible by 3 or 5 (but not 15)
            }

            strBeingSearched = strBeingSearched.substring(matcher.end());
            matcher = pattern.matcher(strBeingSearched); //Replace string/matcher and repeat
        }

        System.out.println(total);
    }   
}
  • Ciąg, który będzie przeszukiwany, może mieć dowolną długość, ale wzorzec będzie tylko jednym znakiem.
  • Żaden ciąg nie będzie zawierał znaków specjalnych wyrażenia regularnego.
  • To jest ; najkrótszy program w bajtach wygrywa.
  • Brak standardowych luk.
Daniel M.
źródło
3
Przydałoby się podać kilka innych przykładów testowych. Zwłaszcza te, w których sekwencja ma więcej niż jedną literę.
Reto Koradi,
Dodałem kilka przypadków - mam nadzieję, że to pomaga. Powiedz mi, czy potrzebuję więcej przypadków - to mój pierwszy raz w PPCG.
Daniel M.
Zmienię wymagania, aby sekwencja była tylko jednym znakiem, ponieważ implementacja jest prawie taka sama, ale mniej myląca.
Daniel M.
To jest jak 1-rzadkie pytanie, ale z dodatkiem
FizzBuzz

Odpowiedzi:

32

Funciton , 1840 bajtów

Cholera, ten język nie nadaje się do gry w golfa.

Ten program oczekuje, że pierwszym znakiem danych wejściowych będzie znak do wyszukania, a reszta danych wejściowych do wyszukiwania ciągu. Oznacza to, że aaababędzie wyszukiwał na awejściu aaba(a tym samym na wyjściu 1). Możesz je oddzielić znakiem nowej linii lub spacją ( a aaba), ale tylko dlatego, że dodatkowy znak nowej linii / spacja nie ma znaczenia dla wyniku.

Jak zawsze możesz uzyskać ładniejszy rendering (bez odstępów między wierszami), jeśli wykonasz go $('pre').css('line-height',1)w konsoli przeglądarki.

      ┌───┐
      │╓─╖└─────────────┐
      └╢³╟┐    ┌─────┐ ┌┴┐╓─╖
┌─────┐╙─╜└────┤┌─╖ ┌┴╖│┌┘║¹║
│     ├───────┐└┤²╟─┤·╟┘│ ╙┬╜╔═══════╗
│    ┌┴╖╔═╗┌─╖├┐╘╤╝ ╘╤╝┌┘  └┬╢2097151║
│    │♭║║5╟┤%╟┘└─┴──┐│┌┘┌───┘╚═══════╝
│    ╘╤╝╚═╝╘╤╝╔═╗┌─╖│││┌┴┐┌────┐
│    ┌┴╖   ┌┘ ║3╟┤%╟┘││└┬┘│╔══╗└┐
│  ┌─┤·╟─┐ │  ╚═╝╘╤╝ │└┐  │║21╟┐│
│  │ ╘╤╝ ├─┘┌─────┘  └┐└┐ │╚══╝│└─┐
│ ┌┴╖┌┴╖┌┴╖┌┴╖┌─╖    ┌┴╖│ │┌─╖┌┴─╖│
│┌┤·╟┤?╟┤?╟┤?╟┤+╟────┤³║│ └┤²╟┤>>║└──┐
││╘╤╝╘╤╝╘╤╝╘╤╝╘╤╝    ╘╤╝│  ╘╤╝╘╤═╝╓─╖│
││ │ ┌┴╖┌┴╖┌┴╖┌┴╖╔═╗ ┌┴╖│  ┌┴╖ ├──╢²╟┤
││ └─┤·╟┤·╟┤?╟┤·╟╢1║┌┤·╟┘  │♯║┌┴╖ ╙─╜│
│└──┐╘╤╝╘╤╝╘╤╝╘╤╝╚═╝│╘╤╝   ╘╤╝│¹║┌───┘
└──┐│╔╧╗ └┬─┘ ┌┴╖   │┌┴─╖   │ ╘╤╝│
   ││║1║ ┌┴┐┌─┤?╟───┴┤>>╟┐ ┌┴╖┌┴╖│
   ││╚═╝ └┬┘│ ╘╤╝    ╘══╝│┌┤?╟┤=║│
   │└────┐│╔╧╗     ┌─────┘│╘╤╝╘╤╝│
╔═╗└────┐│├╢0║╔══╗┌┴╖┌─╖ ╔╧╗   └─┘
║ ║     │└┘╚═╝║21╟┤×╟┤♯╟┐║0║
╚╤╝     └──┐  ╚══╝╘═╝╘═╝│╚═╝
 │┌──┴────╖└────────────┘
 ││int→str║
 │╘══╤════╝
┌┴─╖┌┴╖┌─╖╔╗
│>>╟┤³╟┤¹╟╢║
╘═╤╝╘═╝╘═╝╚╝
╔═╧╗
║21║
╚══╝

(1840 bajtów, gdy jest zakodowany jako UTF-16.)

Wyjaśnienie

  • ¹ zwraca pierwszy znak ciągu.
  • ²zlicza liczbę wystąpień znaku na początku danego ciągu. Na przykład, biorąc pod uwagę znak ai ciąg aaba, zwraca 2. Dla ai baazwraca 0.
  • ³wywołuje, ²aby uzyskać liczbę znaków na początku, sprawdza, czy liczba jest podzielna przez 3 i 5 i czy jest równa 1, i określa odpowiedni przyrost / spadek. Usuwa również jeden dodatkowy znak z początku łańcucha (np. Biorąc pod uwagę, aaabbaże usuwa 3 + 1 = 4 znaki, dając ba). Następnie wywołuje się rekurencyjnie z krótszym łańcuchem i dodaje wynik.
  • Wywołania programu głównego w ¹celu usunięcia pierwszego znaku z danych wejściowych oraz wywołania ³z tym znakiem i resztą łańcucha jako osobne argumenty.
Timwi
źródło
10
Nigdy nie będę głosować za Funcitonem.
orlp
14

CJam, 40 36 35 32 30 bajtów

0llcf=e`::*{(_g+Y13515Yb+=(+}/

Dzięki @ MartinBüttner za grę w golfa na 1 bajcie!

Dzięki @AndreaBiondo za grę w golfa na 2 bajtach i torowanie drogi dla kolejnych 3!

Wypróbuj online w interpretatorze CJam .

Jak to działa

0          e# Push a 0 (accumulator).
l          e# Read a line from STDIN.
lc         e# Read a second line and keep only the first character.
f=         e# Check each character from the first line for equality.
           e# This results in 1 for the specified character and 0 for others.
e`         e# Perform run-length encoding.
::*        e# Multiply each element by its number of repetitions.
{          e# For each remaining integer I:
  (_!      e#   Subtract 1, copy and push sign(I-1).
  +        e#   Add the results.
           e#     If I == 0, I-1 + sign(I-1) =  -1 + -1 = -2.
           e#     If I == 1, I-1 + sign(I-1) =   0 +  0 =  0.
           e#     If I >= 2, I-1 + sign(I-1) = I-1 +  1 =  I.
  Y        e#   Push 2.
  13515Yb  e#   Convert 13515 into the array of its binary digits.
  +        e#   Concatenate 2 and the array.
           e#   This pushes [2 1 1 0 1 0 0 1 1 0 0 1 0 1 1].
  =        e#   Retrieve the digit at (index I-1 + sign(I-1))%15.
           e#     If I == 0, this pushes 1.
           e#     Else, if I == 1, this pushes 2.
           e#     Else, if I%15 == 0, this pushes 2.
           e#     Else, if I%3==0 or I%5==0, this pushes 0.
           e#     Else, this pushes 1.
  (        e#   Decrement the result.
  +        e#   Add it to the accumulator.
}/         e#
Dennis
źródło
Możesz zapisać kolejne 2 bajty z zakodowaną w tabeli tabelą wyszukiwania i modułowym indeksowaniem: llcf=e`::*0-{(_!\6563282Zb:(=}%1bwynosi 33 bajty.
Andrea Biondo
@AndreaBiondo To faktycznie zaoszczędziło 3 bajty. Dzięki!
Dennis
7

C, 160 126 125 119 114 109 104 100 bajtów

main(int q,char **z){int i=0,t=0,s=0,a=z[1][0],c;do{if((c=z[2][i])!=a){s+=(!!t)*((t==1)-!(t%3)-!(t%5)+3*!(t%15));t=0;}else{++t;}++i;}while(c);printf("%d\n",s);}

Prawdopodobnie można to poprawić ... To pobiera dane wejściowe z argumentów wiersza poleceń (pierwszy argument to wzorzec, drugi to ciąg znaków). Nie obsługuje wyszukiwania wzorca znaku NULL (\ x00).

EDYCJA ** 126 125 119 114 109 104 100 bajtów **: Po uwzględnieniu sugestii Dennisa i kilku dodatkowych pomysłów (usunięto klauzulę else, połączyłem while w jedną instrukcję i zastosowano odejmowanie zamiast! =). Usunięto także dodatkowy średnik w pętli for (to była właściwie część sugestii Dennisa). Jeszcze bardziej skrócony poprzez usunięcie zmiennych „i” i „a”.

t,s;main(c,z)char**z;{for(;c;t++)if((c=*z[2]++)-*z[1])s+=!!t*((t<2)-!(t%3)-!(t%5)+3*!(t%15)),t=-1;printf("%d",s);}

Usunięto operatory if i negacja („!”) Poprzez nadużywanie operatora potrójnego. Skompresowano kontrole modułowości, używając tego bitowego „ORAZ” oszukać podwójny &&, ponieważ bitowy „&” ma błąd, i umieszczając porównanie (t <2) wewnątrz operatorów trójskładnikowych. Zastąpiłem !! t * (...) przez przeniesienie !! t do operatora trójskładnikowego, co pozwala mi usunąć nawiasy.

Człowieku, naprawdę chcę sprowadzić go poniżej znaku 100 bajtów: S.

t,s;main(c,z)char**z;{for(;c;)(c=*z[2]++)-*z[1]?s+=t%15?t%3&&t%5?t<2:-1:!!t,t=0:t++;printf("%d",s);}

PRZYGOTOWANE rozwiązania: Nie jestem pewien, czy można je uznać za prawidłowe, ale mogę przejść do 93 znaków, jeśli użyję wyjścia (wyjść) zamiast printf ("% d", s). Ale wtedy wynik nie byłby widoczny, byłby to raczej kod powrotu. Jeśli dane wyjściowe są naprawdę konieczne, mogę je również zmniejszyć do 98 bajtów, ale wymagałoby to również wydrukowania wszystkich wartości pośrednich s przed ostateczną odpowiedzią ...

Tob Ernack
źródło
3
Witamy w Programowaniu Puzzle i Code Golf! Nie przetestowałem go dokładnie, ale i,t,s,a;main(c,z)char**z;{a=*z[1];while(c){if((c=z[2][i])!=a)s+=(!!t)*((t<2)-!(t%3)-!(t%5)+3*!(t%15)),t=0;else++t;++i;}printf("%d",s);}powinien działać równie dobrze (i jest o 23 bajty krótszy).
Dennis,
Och, fajna rzecz z zamiany klauzuli if () {} w jedną instrukcję!
Tob Ernack
Jeszcze kilka bajtów: Jeśli zaczniesz mainz for(a=*z[1];c;i++), nie potrzebne są {}wokół if ... else.
Dennis,
4

Rubin, 111 103 96 bajtów

->s,m{s.chars.chunk{|x|x}.reduce(0){|x,(c,g)|l=g.size
x+(c!=m ?0:l<2||l%15<1?1:l%3*l%5<1?-1:0)}}

To wyzwanie zostało zrobione dla Ruby Enumerable#chunk, więc musiałem to opublikować. :)

Test online: http://ideone.com/pG4mAn

Kod jest dość prosty. Oto bardziej czytelna wersja: http://ideone.com/ub3siA .

Cristian Lupascu
źródło
4

Python 3, 361, 300, 296, 263, 256, 237, 229, 188, 178 , 164 bajtów.

Zaoszczędzono 15 bajtów dzięki vaultah z SOPython.
Zaoszczędzono 9 bajtów dzięki Joe Kingtonowi z SOPython.
Oszczędność 11 bajtów dzięki DSM z SOPython.

Po raz pierwszy przesyłam odpowiedź, więc jestem pewien, że może być ona znacznie krótsza. Bierze ciąg testowy jako pierwszą odpowiedź na dane wejściowe, a znak wyszukiwania jako drugą.

t=input()
m=input()
c=u=0
g=iter(t)
while g:
 r=next(g,0)
 if r==0:print(c);g=0
 while r==m:u+=1;r=next(g,0)
 if u:b=u%3<1;v=u%5<1;c+=((0,-1)[b|v],1)[u<2or b&v];u=0

Wersja bez golfa:

import sys
test = sys.argv[1]
match_char = sys.argv[2]
counter = char_counter = 0
char_generator = (c for c in test)
while char_generator:
    try:
        char = next(char_generator)
    except StopIteration:
        print(counter)
        break
    while char == match_char:
        char_counter += 1
        try:
            char = next(char_generator)
        except StopIteration:
            break
    if char_counter == 0:
        continue
    counter += 1 if char_counter == 1 or (char_counter % 3 == 0 and char_counter % 5 == 0) else -1 if char_counter % 3 == 0 or char_counter % 5 == 0 else 0
    char_counter = 0

Odkryłem, że zawiodłem jeden z przypadków testowych.

Morgan Thrapp
źródło
3

Haskell, 120 bajtów

import Data.List
f c=sum.map(v.length).filter((==c).head).group
v 1=1
v n|n%3&&n%5=1|(n%3||n%5)=(-1)|0<1=0
x%y=x`mod`y<1

f wykonuje pracę.

Leif Willerts
źródło
3

Java, 146 152 143 138 139 136 bajtów

  1. Naprawiono błąd.
  2. przesunięto operacje, zmieniono na operację bitową dla %3&%5kontroli.
  3. Skrócone i<2porównanie.
  4. Naprawiono błąd ( %3&%5czek nie działa zgodnie z myślą).
  5. Użyto skrótu do mnożenia, jak widać w rubyowej odpowiedzi @ w0lf .

Zaimplementowane jako BiFunction<String, String, Integer>w Javie 8, daj mi znać, jeśli jest to wymagany pełny program (lub jeśli mogę nawet upuścić java.util.regexprefiks pakietu poniżej).

Powyższa liczba bajtów nie obejmuje nowej linii poniżej, która jest po prostu dodawana do celów formatowania na tej stronie.

(a,b)->java.util.regex.Pattern.compile("[^"+b+"]").splitAsStream(a)
.mapToInt(v->v.length()).map(i->i<2?i:i%15<1?1:i%3*i%5<1?-1:0).sum();

Z grubsza wyjaśnienie:

  1. Zastosuj wyrażenie regularne z wzorcem, który nie pasuje b, tj "[^"+b+"]".
  2. Uzyskaj długość każdego tokena (np "a" -> 1.).
  3. Stosuje się żądany odwzorowanie -1, 0i 1.
  4. sum() aby uzyskać odpowiedź.
hjk
źródło
2

JavaScript, 206 bajtów

function f(n,e){var t=n.match(new RegExp(e,"g")).length,g=n.match(new RegExp(e+"{2,}","g"));return null!==g&&g.forEach(function(n){t-=n.length,n.length%15==0?t+=1:(n.length%3==0||n.length%5==0)&&(t-=1)}),t}

Rozszerzony:

function funkyFizzb(n, c) {
    var score = n.match(new RegExp(c, "g")).length; 
    var repeatOccurence = n.match(new RegExp(c + "{2,}", "g"));

    if(repeatOccurence !== null) {
        repeatOccurence.forEach(function(v,i){
            // remove multiple occurrence counts
            score -= v.length;

            if(v.length % 15 == 0) {
                score += 1;
            }

            else if(v.length % 3 == 0 || v.length % 5 == 0) {
                score -= 1;
            }
        });
    }

    return score;
};

Wyjaśnienie:

Używam wyrażenia regularnego, aby policzyć całkowitą liczbę pojawień się postaci, a następnie odejmij od niej wszystkie czasy pojawienia się w grupach. Na koniec przeglądam grupy i wykonuję przyrost / dekrement szumu.

Przechodzi przypadki testowe podane w pytaniu:

funkyFizzb("aaa", "a") => -1

i tak dalej

jestem poważny
źródło
Usuń new, użyj execzamiast matchi alias length, i powinieneś być dobry.
Mama Fun Roll
2

Perl, 82 65 63 59 bajtów

58 bajtów + 1 bajtowy parametr wiersza poleceń

Niezbyt krótki, ale to początek - będzie nadal go skracał.

$l=y///c,$i+=!($l>1&&$l%15)||-!($l%3*$l%5)for/$^I+/g;$_=$i

Zakładając, że -imożna podać ciąg wejściowy przykładowe użycie, wygląda następująco:

echo "aaabaaa" | perl -pi"a" entry.pl
Jarmex
źródło
0

Pyth, 32 bajty

tak blisko! Jeszcze 2 bajty, aby powiązać doskonałe wejście Dennisa do CJam

s.b?qYz?tN@+,0_1 1+}3PN}5PN1Zrw8

Przetestuj online

Brian Tuck
źródło
0

gawk, 140

p=$2{b="[^"$1"]";for($0=2;$i-->0;){sub("^"b"*",_,p);p=substr(p,$++i=match(p,b))}for($i=length(p);$++j;)s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1}$0=s""

Wprowadź jako „ciąg znaków char”, podobnie jak

echo "x axxbxcxdexxxfffghixxj" | awk 'p=$2{b="[^"$1"]";for($0=2;$i-->0;){sub("^"b"*",_,p);p=substr(p,$++i=match(p,b))}for($i=length(p);$++j;)s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1}$0=s""'

Nie golfił

p=$2{
    #i=j=s=0                # make reusable
    b="[^"$1"]";           # pattern "not matching char"
    $0=2;                  # help starting the while loop
    while($i-->0){         # match didn't return -1; dec stack top
        sub("^"b"*",_,p);  # remove not matching chars at head of string
        $++i=match(p,b);   # push index of first occurence of not matching char
        p=substr(p,$i)     # remove matching chars from head of string
    };
    $i=length(p);          # get last value
    while($++j)            # sometimes last value on stack is 0
        s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1

        # if $j%5!=0
        #   if $j%3!=0     (not divisible by 5 AND 3)
        #     s+=($j==1)   (single character)
        #   else           (divisible by 3 but not by 5)
        #     s-=1
        # else             (divisble by 5)
        #   if $j%3!=0
        #     s-=1         (divisible by 5 but not by 3)
        #   else
        #     s+=1         (divisible by 3 AND 5)

}$0=s"" # output
Cabbie407
źródło
0

Pyth, 27 bajtów

sm|!JPdx,02+}3J}5JhMf}zTrw8

Zestaw testowy

Wprowadź w formularzu np .:

a
aaaba

Wyjaśnienie:

sm|!JPdx,02+}3J}5JhMf}zTrw8
                               z = input() (The match character)
                         w     input() (The string)
                        r 8    Run length encode
                    f}zT       Filter for the runs z is in.
                  hM           Take their lengths
 m|                            Map (d) to the logical or of
    Pd                         Find all prime factors of the current run length
   J                           Save them in J
  !                            Take the logical negation. This will be 1 if
                               d is 1, and 0 otherwise.
           +}3J                If d wasn't 1, add up 1 if 3 is in J
               }5J             and 1 if 5 is in J.
       x,02                    Then, take the index of the result in [0,2]
                               so 0 -> 0, 2 -> 1, 1 -> -1 (not found)
s                              Sum up the values for each run.
isaacg
źródło