A sequência X é uma subsequência da sequência Y?

23

Dadas as cadeias X e Y, determine se X é uma subsequência de Y. A cadeia vazia é considerada uma subsequência de todas as cadeias. (Por exemplo, ''e 'anna'são subsequências de 'banana'.)

Entrada

  • X, uma sequência alfanumérica possivelmente sensível a maiúsculas e minúsculas
  • Y, uma sequência alfanumérica sensível a maiúsculas e minúscula

Saída

  • Verdadeiro ou falso (ou equivalente), indicando corretamente se X é uma subsequência de Y.

Exemplos de E / S

X      Y        output

''     'z00'    True
'z00'  'z00'    True 
'z00'  '00z0'   False
'aa'   'anna'   True
'anna' 'banana' True
'Anna' 'banana' False

Critério

  • O programa mais curto vence, conforme determinado pelo número de bytes do código fonte.

Programas de exemplo

res
fonte
1
Por que é 'anna' substr de 'banana'?
kaoD
4
@kaoD - annaé uma subsequência (mas não uma substring) de banana. A cadeia X é uma subsequência da cadeia Y apenas se X puder ser obtido de Y excluindo zero ou mais dos elementos de Y; por exemplo, excluir o be o segundo ade bananadoações anna.
res
2
Isso tem uma solução única em todas as linguagens de script que oferecem expressões regulares que são triviais de ver e impossíveis de jogar.
JoeyAbr

Respostas:

18

Perl 5 , 17 bytes (+1?), Programa completo

s//.*/g;$_=<>=~$_

Experimente online!

Invoque com o psinalizador para o interpretador perl, como em perl -pe 's//.*/g;$_=<>=~$_'. De acordo com as regras de pontuação estabelecidas quando este desafio foi lançado originalmente , esse sinalizador custa um byte extra. Sob regras mais recentes , AFAICT, pode ser gratuito.

De qualquer forma, as cadeias de entrada devem ser fornecidas em linhas separadas por nova linha no stdin. A saída (para stdout) será 1se a primeira string de entrada for uma subcadeia da segunda, ou nada se não for.

Observe que ambas as linhas de entrada devem ter uma nova linha no final, ou o programa não funcionará corretamente. Como alternativa, você pode adicionar o lsinalizador de linha de comando à chamada para fazer com que o perl descubra as novas linhas; dependendo das regras de pontuação em vigor, isso pode ou não custar um byte extra. Observe que o uso desse sinalizador também acrescentará uma nova linha à saída.

Versão original (fragmento, 18 bytes / caracteres)

$x=~s//.*/g,$y=~$x

A entrada é fornecida nas variáveis $xe $y, result é o valor da expressão (no contexto escalar). Observe que $xé modificado no processo. (Sim, eu sei que usar em $_vez de $xme permitiria salvar quatro caracteres, mas fazer isso em um snippet que parece um pouco brega demais para mim.)

Como funciona?

A primeira parte $x=~s//.*/g,, insere a sequência .*entre cada caractere $x. A segunda parte ,, $y=~$xtrata $xcomo uma expressão regular e combina $ycom ela. Nas regexps Perl, .*corresponde a zero ou mais caracteres arbitrários, enquanto todos os caracteres alfanuméricos se combinam convenientemente.

Ilmari Karonen
fonte
De acordo com o consenso (novo?), As submissões devem ser de programa ou função, não snippet. Se o seu envio não satisfizer isso, considere editá-lo.
user202729
@ user202729: Esse desafio é muito mais antigo que esse consenso. Portanto, a menos que se suponha que se aplique retroativamente, as respostas neste tópico provavelmente devem ser "avô". Dito isso, acabei de adicionar uma versão que esteja em conformidade com as regras atuais e pode até ser um byte / char mais curto (observe que a contagem baseada em bytes também é mais recente que esse desafio, AFAIK), dependendo de como você conta as opções da linha de comando.
Ilmari Karonen 26/03/19
9

Ruby, 32 caracteres

s=->x,y{y=~/#{[*x.chars]*".*"}/}

Esta solução retorna nilse xnão for uma subsequência de ye um número de outra forma (ou seja, equivalentes a ruby falsee e true). Exemplos:

p s['','z00']        # => 0   (i.e. true)
p s['z00','z00']     # => 0   (i.e. true)
p s['z00','00z0']    # => nil (i.e. false)
p s['anna','banana'] # => 1   (i.e. true)
p s['Anna','banana'] # => nil (i.e. false)
Howard
fonte
1
Eu fiz basicamente a mesma coisa, mas é muito parecida, então não vou publicá-la. Eu acho que é aceitável deixar de fora o lambda, o que deixaria você com y=~/#{[*x.chars]*".*"}/(23 caracteres). Felicidades!
Patrick Oscity
1
ou mesmo y=~/#{x.split("")*".*"}/(21 caracteres) :)
Patrick Oscity
@padde O split one é na verdade 24 caracteres.
274 Howard
1
Desculpe, eu acho que eu acidentalmente deixado de fora da y=~enquanto mexer com esta no IRB ...
Patrick Oscity
Minha versão é 2 caracteres mais curta.
Hauleth
7

Haskell, 51 37.

h@(f:l)%(g:m)=f==g&&l%m||h%m;x%y=x<=y

Agradecemos a Hammar pela melhoria substancial. Agora é uma função infix, mas parece não haver razão para que não deva.

Demonstração:

GHCi> :{
GHCi| zipWith (%) [""   , "z00", "z00" , "anna"  , "Anna"]
GHCi|             ["z00", "z00", "00z0", "banana", "banana"]
GHCi| :}
[True,True,False,True,False]
deixou de girar contra-relógio
fonte
Como a lista vazia é menor que qualquer outra lista, você pode simplificar os casos base para s x y=x<=y. Além disso, você pode economizar um pouco mais, tornando-o um operador e usando um @padrão-em vez de (f:l). Isso reduz para 37 caracteres:h@(f:l)%(g:m)=f==g&&l%m||h%m;x%y=x<=y
hammar
6

Python (48 caracteres)

import re;s=lambda x,y:re.search('.*'.join(x),y)

A mesma abordagem que a resposta Ruby de Howard. Pena que o Python precise importar o pacote regex e seu "verbose" lambda. :-)

Eric
fonte
1
Eu concordo, lambda é detalhado.
CalculatorFeline
4

Python, 59 caracteres

def s(x,y):
 for c in y:
  if x:x=x[c==x[0]:]
 return x==""

Imaginei que minha resposta seria melhor expressa em Python.

Editar: Adicionado sugestões de res.

Gareth
fonte
Certamente dado x="a"e y="ab"você sairia do loop com y=="b"e retornaria false?
Peter Taylor
@PeterTaylor Sim, eu notei quando eu estava correndo os exemplos como testes após postagem que eu tenho mista xe ypara cima. Em minhas funções yprecisa ser uma subsequência de x. Acho melhor mudá-los para evitar qualquer confusão.
Gareth
Você pode obter este até 59 caracteres: def s(x,y): for c in y: if x:x=x[c==x[0]:] return x=="". Ele não é exibido corretamente em um comentário, mas acho que você pode entender o que quero dizer. (Além disso, um espaço adicional é suficiente para aumentar o nível de recuo.)
res
@res Obrigado, Python não é uma linguagem que eu uso tanto quanto você provavelmente sabe. Bom golfe. (63 caracteres de acordo com o script de usuário do Codegolf - deve estar contando as novas linhas).
Gareth
1
Você pode usar estendendo corte para proteger contra sendo X ''e salvar vários caracteres escrevendox=x[c==x[0:1]:]
Nolen Royalty
4

GolfScript (22 caracteres)

X[0]+Y{1$(@={\}*;}/0=!

Assume que a entrada é tomada como duas variáveis ​​predefinidas Xe Y, embora isso seja bastante incomum no GolfScript. Folhas 1para verdadeiro ou 0falso na pilha.

Peter Taylor
fonte
4

C (52 caracteres)

s(char*x,char*y){return!*x||*y&&s(*x-*y?x:x+1,y+1);}

Casos de teste

Peter Taylor
fonte
s(char*x,char*y){x=!*x||*y&&s(x+(*x==*y),y+1);}
L4m2 26/0318
4

Burlesco (6 caracteres)

6 caracteres em burlesco: R@\/~[ (supondo que xey estejam na pilha. Veja aqui em ação.)

mroman
fonte
3

PHP, 90 caracteres

<?function s($x,$y){while($a<strlen($y))if($y[$a++]==$x[0])$x=substr($x,1);return $x=="";}
Gareth
fonte
Você pode remover a ifinstrução e simplificar para $x=substr($x,$y[$a++]==$x[0]): ideone.com/Ch9vK
mellamokb 16/04/12
Também aqui é um pouco mais curto solução 82 caracteres usando recursão: ideone.com/IeBns
mellamokb
3

Scala 106:

def m(a:String,b:String):Boolean=(a.size==0)||((b.size!=0)&&((a(0)==b(0)&&m(a.tail,b.tail))||m(a,b.tail)))
Usuário desconhecido
fonte
3

CoffeeScript 112 100 95 89

Minha primeira tentativa no código de golfe ... espero não envergonhar minha família!

z=(x,y)->a=x.length;return 1if!a;b=y.indexOf x[0];return 0if!++b;z x[1..a],y[b..y.length]

Edit : Acontece que Coffeescript é mais tolerante do que eu pensava com espaço em branco.

Obrigado a res e Peter Taylor por algumas dicas para torná-lo um pouco mais elegante

Johno
fonte
Mais alguns caracteres pode ser eliminada do seguinte modo (isto não irá exibir direita em um comentário, mas eu acho que você pode ver o que quero dizer): z=(x,y)-> a=x.length return 1if a==0 b=y.indexOf x[0] return 0if b<0 z x[1..a],y[b+1..y.length]. (Em alguns navegadores, por exemplo, Chrome, você pode ver comentário de código exibido corretamente clicando com o botão direito, em seguida, Inspect Element.)
res
a.lengthnunca será negativo; portanto, você pode salvar mais um caractere substituindo if a==0por if a<1. Não sei como funciona a tokenização do CoffeeScript, mas, se houver if0dois tokens, você poderá economizar mais dois, revertendo as duas condições (ou seja if1>a).
Peter Taylor
Bons pontos. if1>anão é válido, mas if!aé e é um personagem mais curto! Também percebi que podia barbear um caractere extra convertendo b+1-o be incrementando-o na linha anterior, tornando ifpossível o mesmo truque, pois estava lidando com uma situação de 0 / não-0.
31412 Johno
3

C #, 70 113 107 90 caracteres

static bool S(string x,string y){return y.Any(c=>x==""||(x=x.Remove(0,c==x[0]?1:0))=="");}
mizer
fonte
6
Isso não procura uma substring em vez de uma subsequência?
Gareth
sim, eu interpretei errado. Deve ser corrigido agora.
mizer
1
Por mais divertido que seja o Linq, acho que você pode economizar 10% usando a recursão.
Peter Taylor
Aqui está a minha melhor tentativa. Ainda mais. static bool S(string x,string y){if(x!=""&&y=="")return false;return x==""||S(y[0]==x[0]?x.Remove(0,1):x,y.Remove(0,1));}
mizer
Você pode reduzir o recursivo para x==""||y!=""&&S(...), mas ainda é maior que a versão atualizada do Linq. Bom uso de Any!
Peter Taylor
3

Mathematica 19 17 27

LongestCommonSequenceretorna a subsequência não contígua mais longa de duas seqüências. (Não deve ser confundido com LongestCommonSubsequence, que retorna a subsequência contígua mais longa.

A seguir, verifica se a subsequência contígua mais longa é a primeira das duas seqüências. (Portanto, você deve inserir a sequência mais curta seguida pela sequência maior.)

LongestCommonSequence@##==#& 

Exemplos

LongestCommonSequence@## == # &["", "z00"]
LongestCommonSequence@## == # &["z00", "z00"]
LongestCommonSequence@## == # &["anna", "banana"]
LongestCommonSequence@## == # &["Anna", "banana"]

Verdadeiro Verdadeiro Verdadeiro Falso

O teste crítico é o terceiro, porque "anna" está contido de forma não contígua na "banana".

DavidC
fonte
3

Python 3.8 (pré-lançamento) , 42 bytes

lambda a,b:''in[a:=a[a[:1]==c:]for c in b]

Experimente online!

Python 3.8 (pré-lançamento) , 48 bytes

lambda a,b,j=0:all((j:=1+b.find(c,j))for c in a)

Experimente online!

Python 2 , 48 bytes

lambda a,b:re.search('.*'.join(a),b)>0
import re

Experimente online!

Copiado desta resposta de Lynn . O >0pode ser omitido se apenas truthy / Falsey saída é OK.

Python 2 , 50 bytes

f=lambda a,b:b and f(a[a[:1]==b[0]:],b[1:])or''==a

Experimente online!

Python 2 , 50 bytes

lambda a,b:reduce(lambda s,c:s[c==s[:1]:],b,a)==''

Experimente online!

xnor
fonte
Grande uso da morsa.
Jonathan Allan
2

C - 74 71 64

Isso não supera a solução de Peter Taylor, mas acho que é bem divertido (além disso, este é um programa de trabalho completo, não apenas uma função)

main(int c,char**v){for(;*v[1]!=0;++v[1])v[2]+=*v[1]==*v[2];return*v[2];}

main(int c,char**v){for(;*v[1];++v[1])v[2]+=*v[1]==*v[2];return*v[2];}


main(c,v)char**v;{while(*v[1])v[2]+=*v[1]++==*v[2];return*v[2];}

E não destruído:

main(int argc, char** argv){
   char * input = argv[1];
   char * test  = argv[2];

   // advance through the input string. Each time the current input
   // character is equal to the current test character, increment
   // the position in the test string.

   for(; *input!='\0'; ++input) test += *input == *test;

   // return the character that we got to in the test string.
   // if it is '\0' then we got to the end of the test string which
   // means that it is a subsequence, and the 0 (EXIT_SUCCESS) value is returned
   // otherwise something non-zero is returned, indicating failure.
   return *test;
}

Para testá-lo, você pode fazer algo como:

./is_subsequence banana anna && echo "yes" || echo "nope"    
# yes
./is_subsequence banana foobar && echo "yes" || echo "nope"    
# nope
Gordon Bailey
fonte
!=0em uma condição é um pouco detalhado ... Programa versus função é algo que a pergunta precisa especificar claramente, e aqui não, então as respostas têm opções diferentes.
Peter Taylor
Porra, isso !='\0'é um péssimo (bom?) Hábito de escrever código que não seja de golfe. Eu deixei isso entrar nas minhas duas últimas rodadas de golfe; terei que ter mais cuidado no futuro. Quanto ao programa versus função, sim, você está absolutamente certo.
Gordon Bailey
@GordonBailey, desculpe pela colisão, mas fiz algumas alterações em uma versão mais curta.
oldrinb
2

Python, 66. 62 59. 58 caracteres

Uma solução divertida, definitivamente um problema interessante.

def f(n,h,r=0):
 for c in h:r+=n[r:r+1]==c
 return r==len(n)
Realeza Nolen
fonte
2

Ruby 32 30 28

f=->a,b{b.match a.tr'','.*'}

Isso retornará a MatchDatainstância se afor subsequente bou nilnão.

Versão antiga que encontra substring em vez de subsequência

Ruby 15

f=->a,b{!!b[a]}

Usando o String#[](str)método que retorna strif stré uma substring de selfe !!para retornar Booleanse o valor retornado pode ser usado como booleano (e não precisa ser trueor false), pode ser de apenas 13 caracteres:

f=->a,b{b[a]}

Ele retornará nilse anão for uma substring de b.

Hauleth
fonte
2
Bom, mas a pergunta pede uma subsequência em vez de uma substring.
Gareth
2

SWI-Prolog, SICStus

O predicado interno sublist / 2 do SICStus verifica se todos os itens na primeira lista também aparecem na segunda lista. Esse predicado também está disponível no SWI-Prolog através da biblioteca de compatibilidade, que pode ser carregada pela consulta [library(dialect/sicstus/lists)]..

Exemplo de execução:

25 ?- sublist("","z00").
true.

26 ?- sublist("z00","z00").
true .

27 ?- sublist("z00","00z0").
false.

28 ?- sublist("aa","anna").
true .

29 ?- sublist("anna","banana").
true .

30 ?- sublist("Anna","banana").
false.

Tecnicamente, a contagem de bytes pode ser 0, uma vez que tudo o que estamos fazendo aqui é a consulta, assim como executamos um programa e fornecemos entrada para ele.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
fonte
2

PHP, 41 bytes

imprime 1 para verdadeiro e nada para falso

<?=!levenshtein($argv[1],$argv[2],0,1,1);

Se apenas inserções da palavra 1 à palavra 2 concluídas, a contagem é zero para casos verdadeiros

levenshtein

Experimente online!

PHP, 57 bytes

imprime 1 para verdadeiro e 0 para falso

Cria um Regex

<?=preg_match(_.chunk_split($argv[1],1,".*")._,$argv[2]);

Experimente online!

Jörg Hülsermann
fonte
1
-2 bytes: o avanço .*é desnecessário. -2 bytes: não atribuir $argva $a. +24 bytes: necessidades array_map(preg_quote())de caracteres especiais (Use parênteses como delimitadores para evitar segundo preg_quoteparâmetro.)
Titus
2
@Titus o primeiro. * É necessário para a entrada de uma string vazia e para a entrada eu devo lidar apenas com uma string alfanumérica sensível a maiúsculas e minúsculas. Você está certo com a citação se houver caracteres especiais. Obrigado por contar o trabalho. Copie e cole por uma solução anterior e não pense nisso
Jörg Hülsermann 14/03
1
preg_matchnão reclamará de uma regex vazia enquanto os delimitadores estiverem lá. Combina apenas com qualquer coisa. Mas preg_quote é de apenas 22 bytes, não +24: array_map(preg_quote,str_split(...)).
Titus
1
Porém, a entrada é garantida como alfanumérica :) Mas você ainda não precisa da liderança .*.
Titus
2

Braquilog , 2 bytes

⊆ᵈ

Experimente online!

Como com esta resposta, é um predicado interno que declara um relacionamento entre as variáveis ​​de entrada e saída e é um meta-predicado que o modifica para declarar o mesmo relacionamento entre o primeiro e o segundo elementos da variável de entrada (e unificar a variável de saída com o segundo elemento, mas como esse é um problema de decisão que não acaba importando aqui). X⊆Yé uma afirmação de que X é uma subsequência de Y, portanto, é [X,Y]⊆ᵈ.

Esse predicado (que, é claro, gera sucesso ou falha que é impressa true.ou false.quando é executado como um programa) recebe a entrada como uma lista de duas seqüências. Se a entrada é um pouco mais flexível ...

Braquilog , 1 byte

Experimente online!

Leva a string X como a variável de entrada e a string Y como a variável de saída. Saídas por sucesso ou fracasso, como antes. Se executado como um programa completo, X é fornecido como entrada e Y é fornecido como o primeiro argumento da linha de comandos.

String não relacionada
fonte
1

CoffeeScript 73

Aqui está uma resposta alternativa do CoffeeScript, usando expressões regulares em vez de recursão:

z=(x,y)->a='.*';a+=c+'.*'for c in x;b=eval('/'+a+'/');(y.replace b,'')<y

Se o palheiro corresponder a um regex muito ganancioso construído a partir da agulha, ele será substituído por um fio vazio. Se o palheiro é mais curto do que começou, a agulha foi uma subsequência.

Retorna false quando xe ysão duas strings vazias. Pense que precisamos de um filósofo para nos dizer se uma sequência vazia é uma subsequência de si mesma!

(Publicado como uma resposta separada da minha anterior, porque parece diferente o suficiente para justificá-la).

Johno
fonte
1

PowerShell, 38

$args[1]-clike($args[0]-replace'','*')

Obviamente, qualquer solução baseada em correspondência de padrão ou regex tem graves problemas de desempenho com cadeias mais longas. Mas como a falta é o critério ...

Joey
fonte
1

Uma espécie de anti-solução gerando todas as subsequências de Y:

Python 93

l=len(y)
print x in[''.join(c for i,c in zip(bin(n)[2:].rjust(l,'0'),y)if i=='1')for n in range(2**l)]
daniero
fonte
1

APL (31)

O manuseio de strings é um pouco ausente no APL.

{(⊂'')∊N←⍵↓⍨¨1,⍨=/⊃¨⍵:~×⍴⊃N⋄∇N}

uso:

      {(⊂ '') ∊N ← ⍵ ↓ ⍨¨1, ⍨ = / ⊃¨⍵: ~ × ⍴⊃N⋄∇N} 'anna' 'banana'
1
      {(⊂ '') ∊N ← ⍵ ↓ ⍨¨1, ⍨ = / ⊃¨⍵: ~ × ⍴⊃N⋄∇N} 'Anna' 'banana'
0 0
      {(⊂ '') ∊N ← ⍵ ↓ ⍨¨1, ⍨ = / ⊃¨⍵: ~ × ⍴⊃N⋄∇N} '' 'banana'
1
marinus
fonte
1

Python 132

Semelhante ao Daniero. Não é a solução mais fácil, mas foi divertido tentar. Eu sou novo no Python, então tenho certeza de que poderia reduzi-lo se soubesse um pouco mais.

def f(i):
    s=x;j=0
    while j<len(s):t=~i%2;s=[s[:j]+s[j+1:],s][t];j+=t;i>>=1
    return s==y
print True in map(f,range(1,2**len(x)))
cortador
fonte
1

Python - 72

def f(a,b):
 c=len(a)
 for i in b:a=a.replace(i,"",1)
 print len(a+b)==c
Homem de codificação
fonte
1

Python ( 75 52)

s=lambda a,b:a==''or b>''and s(a[a[0]==b[0]:],b[1:])

Solução recursiva simples. Golfe pela primeira vez, por isso todas as dicas sobre como reduzir isso são muito apreciadas :)

Testado com o seguinte:

assert s('anna', 'banana') == True
assert s('oo0', 'oFopp0') == True
assert s 'this', 'this is a string') == True
assert s('that', 'this hat is large') == True
assert s('cba', 'abcdefg') == False

Obrigado a @lirtosiast por alguns truques booleanos inteligentes.

foslock
fonte
1
Você pode obter isso em 52 caracteres:s=lambda a,b:a==''or b>''and s(a[a[0]==b[0]:],b[1:])
lirtosiast
Obrigado, isso é inteligente, usando o boolean como o 0/1 índice para a emenda :)
foslock
1

PHP, 75 65 64 bytes

for(;$p=@strpos(_.$argv[2],$c=$argv[1][$i++],$p+1););echo""==$c;

recebe entrada de argumentos de linha de comando; imprime 1para true, string vazia para false. Corra com -r.

explicação:

  • strposretorna falsese a agulha $cnão estiver no palheiro $argv[2](depois da posição $p),
    causando a ruptura do laço.
  • strpostambém retorna falsepara uma agulha vazia, interrompendo o ciclo no final de$argv[1] .
  • Se $argv[1]é uma subsequência de $argv[2],$c ficará vazio quando o loop for interrompido.
  • strposprecisa @suprimir o Empty needleaviso.
Titus
fonte
+$pem vez de $p+1depois disso, não há necessidade de sublinhado
Jörg Hülsermann 14/03
O @ JörgHülsermann +1é necessário para avançar na corda do palheiro; e o sublinhado evita a $p=-1inicialização. Mas ... eu posso evitar false!==.
Titus
1

Swift, 27

print(Y.range(of:X) != nil)
Dimitrie-Toma Furdui
fonte
Bem-vindo ao PPCG!
Martin Ender