Является ли строка X подпоследовательностью строки Y?


23

По заданным строкам X и Y определите, является ли X подпоследовательностью Y. Пустая строка рассматривается как подпоследовательность каждой строки. (Например, ''и 'anna'являются подпоследовательности 'banana'.)

вход

  • X, возможно пустая чувствительная к регистру буквенно-цифровая строка
  • Y, возможно пустая буквенно-цифровая строка с учетом регистра

Выход

  • True или False (или эквиваленты), правильно указывающие, является ли X подпоследовательностью Y.

Примеры ввода / вывода

X      Y        output

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

критерии

  • Самая короткая программа выигрывает, что определяется количеством байтов исходного кода.

Примеры программ

  • Несколько программ, которые могут быть адаптированы, находятся в этой публикации .

1
Почему «анна» является субстратом «банана»?
2012 г.

4
@kaoD - annaэто подпоследовательность (но не подстрока) banana. Строка X является подпоследовательностью строки Y, только если X можно получить из Y, удалив ноль или более элементов из Y; например, удаление bи второй aиз bananaдает anna.
Res

2
Это имеет единственное решение на каждом языке сценариев, предлагающее регулярные выражения, которые тривиально увидеть и которые невозможно продвинуть дальше.
Джои

Ответы:


18

Perl 5 , 17 байт (+1?), Полная программа

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

Попробуйте онлайн!

Вызвать с pфлагом для интерпретатора Perl, как в perl -pe 's//.*/g;$_=<>=~$_'. В соответствии с установленными правилами оценки, когда этот вызов был первоначально опубликован , этот флаг стоит один дополнительный байт. По более новым правилам , AFAICT, это может быть бесплатно.

В любом случае, входные строки должны предоставляться в отдельных строках с новой строкой в ​​stdin. Вывод (в stdout) будет, 1если первая входная строка является подстрокой второй, или вообще ничего, если это не так.

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

Оригинальная версия (фрагмент, 18 байт / символов)

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

Входные данные даны в переменных $xи $y, результатом является значение выражения (в скалярном контексте). Обратите внимание, что $xизменяется в процессе. (Да, я знаю, что использование $_вместо $xпозволит мне сохранить четыре символа, но делает это в фрагменте кода, который кажется мне слишком глупым.)

Как это работает?

Первая часть, $x=~s//.*/gвставляет строку .*между каждым символом в $x. Вторая часть, $y=~$xрассматривается $xкак регулярное выражение и сопоставляется $yс ним. В регулярных выражениях Perl .*совпадает ноль или более произвольных символов, в то время как все буквенно-цифровые символы удобно совпадают.


Согласно нашему (новому?) Консенсусу, заявки должны быть программными или функциональными, а не фрагментами. Если ваша заявка не удовлетворяет этому, рассмотрите возможность ее редактирования.
user202729

@ user202729: Эта задача намного старше, чем этот консенсус, поэтому, если не предполагается, что она применяется задним числом, ответы в этой теме, вероятно, должны быть «найдены». Тем не менее, я просто добавила версию, которая соответствует текущим правилам, и может даже быть на один байт / символ короче (обратите внимание, что подсчет на основе байтов также новее, чем этот вызов, AFAIK), в зависимости от того, как вы подсчитываете параметры командной строки.
Илмари Каронен

9

Рубин, 32 символа

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

Это решение возвращает, nilесли xне является подпоследовательностью yи числом в противном случае (т. Е. Рубиновые эквиваленты falseи true). Примеры:

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)

1
я сделал в основном то же самое, но это слишком похоже, поэтому я не буду публиковать его. я думаю, что приемлемо оставить лямбду, которая оставила бы вас с y=~/#{[*x.chars]*".*"}/(23 символа). ура!
Патрик Осцити

1
или даже y=~/#{x.split("")*".*"}/(21 символ) :)
Patrick Oscity

@padde Сплит на самом деле 24 символа.
Говард

1
извините, я полагаю, что я случайно перестал y=~с этим возиться в irb ...
Патрик Осцити

Моя версия на 2 символа короче.
Хаулет

7

Haskell, 51 37

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

Спасибо Хаммару за существенное улучшение. Теперь это инфиксная функция, но, похоже, нет причин, по которым она не должна этого делать.

Демонстрация:

GHCi> :{
GHCi| zipWith (%) [""   , "z00", "z00" , "anna"  , "Anna"]
GHCi|             ["z00", "z00", "00z0", "banana", "banana"]
GHCi| :}
[True,True,False,True,False]

Поскольку пустой список меньше любого другого списка, вы можете упростить базовые варианты до s x y=x<=y. Кроме того, вы можете сэкономить еще немного, сделав его оператором и используя @-pattern вместо (f:l). Это сокращает до 37 символов:h@(f:l)%(g:m)=f==g&&l%m||h%m;x%y=x<=y
Hammar

6

Python (48 символов)

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

Тот же подход, что и у Рубарда. Жаль, что в Python нет необходимости импортировать пакет регулярных выражений и его «подробный» lambda. :-)


1
Я согласен, лямбда многословна.
CalculatorFeline

4

Python, 59 символов

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

Я подумал, что мой ответ будет лучше выражен в Python.

Изменить: Добавлены предложения Res.


Конечно, x="a"и y="ab"вы бы выйти из цикла y=="b"и вернуться false?
Питер Тейлор

@PeterTaylor Да, я заметил, когда запускал примеры в качестве тестов после публикации, что я перепутал xи перепутал y. В моих функциях yдолжна быть подпоследовательность x. Я думаю, что лучше поменять их, чтобы избежать путаницы.
Гарет

Вы можете получить это вниз до 59 символов: def s(x,y): for c in y: if x:x=x[c==x[0]:] return x=="". Он не отображается правильно в комментарии, но я думаю, вы понимаете, о чем я. (Кроме того, для увеличения уровня отступа достаточно одного дополнительного пробела.)
res

@res Спасибо, Python - это не тот язык, которым я пользуюсь, как вы, вероятно, можете сказать. Хороший гольф. (63 символа в соответствии с пользовательским сценарием Codegolf - это должен быть перевод строки).
Гарет

1
Вы можете использовать расширенную нарезку, чтобы защитить от существа х ''и сохранить несколько символов, написавx=x[c==x[0:1]:]
Nolen Royalty

4

GolfScript (22 символа)

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

Предполагается, что ввод берется как две предопределенные переменные Xи Y, хотя это довольно необычно в GolfScript. Оставляет в стеке значение 1true или 0false.



4

Бурлеск (6 символов)

6 символов в бурлеск: R@\/~[ (при условии, что x и y находятся в стеке. Смотрите здесь в действии.)



3

PHP, 90 символов

<?function s($x,$y){while($a<strlen($y))if($y[$a++]==$x[0])$x=substr($x,1);return $x=="";}

Вы можете удалить ifутверждение и упростить до $x=substr($x,$y[$a++]==$x[0]): ideone.com/Ch9vK
mellamokb

Также здесь представлено несколько более короткое 82-символьное решение с использованием рекурсии: ideone.com/IeBns
mellamokb


3

CoffeeScript 112 100 95 89

Моя первая попытка в гольф-коде ... надеюсь, я не позорю свою семью!

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]

редактировать : оказывается, Coffeescript более прощающий, чем я думал с пробелами.

Спасибо res и Peter Taylor за несколько советов, как сделать его немного изящнее


Еще несколько символов могут быть устранены следующим образом (это не будет отображаться прямо в комментариях, но я думаю , что вы можете увидеть , что я имею в виду) 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]. (В некоторых браузерах, например, Chrome, код комментария можно правильно отобразить, щелкнув правой кнопкой мыши, затем «Проверить элемент».)
res

a.lengthникогда не будет отрицательным, поэтому вы можете сохранить еще один символ, заменив его if a==0на if a<1. Я не знаю, как работает токенизация CoffeeScript, но если он использует if0два токена, вы можете сохранить еще два, поменяв оба условия (то есть if1>a).
Питер Тейлор

Хорошие моменты. if1>aне действителен, но if!aесть и является символом короче! Я также понял , что я мог бы сбрить дополнительный характер преобразование b+1в bи приращении его на предыдущей строке, также делает тот же ifтрюк , возможно , так как она имеет дело с 0 / не-0 ситуацией.
Джоно

3

C #, 70 113 107 90 символов

static bool S(string x,string y){return y.Any(c=>x==""||(x=x.Remove(0,c==x[0]?1:0))=="");}

6
Разве это не поиск подстроки, а не подпоследовательности?
Гарет

да, я неправильно прочитал Должно быть исправлено сейчас.
Мизер

1
Как бы ни был интересен Linq, я думаю, что вы можете сэкономить 10%, используя вместо этого рекурсию.
Питер Тейлор

Вот моя лучшая попытка. Еще дольше. 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

Вы можете уменьшить рекурсивный до x==""||y!=""&&S(...), но он все же дольше, чем обновленная версия Linq. Хорошее использование Any!
Питер Тейлор

3

Mathematica 19 17 27

LongestCommonSequenceвозвращает самую длинную несмежную подпоследовательность из двух строк. (Не путать с LongestCommonSubsequence, который возвращает самую длинную непрерывную подпоследовательность.

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

LongestCommonSequence@##==#& 

Примеры

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

Истинно верно верно ложно

Критическое испытание - третье, потому что «анна» содержится не непрерывно в «банане».


3

Python 3.8 (предварительная версия) , 42 байта

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

Попробуйте онлайн!

Python 3.8 (предварительная версия) , 48 байт

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

Попробуйте онлайн!

Python 2 , 48 байт

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

Попробуйте онлайн!

Скопировано из этого ответа Линн . Значение >0может быть опущено, если вывод truey / falsey в порядке.

Python 2 , 50 байт

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

Попробуйте онлайн!

Python 2 , 50 байт

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

Попробуйте онлайн!


Большое использование моржа.
Джонатан Аллан

2

C - 74 71 64

Это не побеждает решение Питера Тейлора, но я думаю, что это довольно весело (плюс, это полноценная рабочая программа, а не просто функция)

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];}

И безглым

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;
}

Чтобы проверить это, вы можете сделать что-то вроде:

./is_subsequence banana anna && echo "yes" || echo "nope"    
# yes
./is_subsequence banana foobar && echo "yes" || echo "nope"    
# nope

!=0в состоянии немного многословно ... Программа против функции - это то, что вопрос должен четко указывать, а здесь это не так, поэтому ответы имеют разные варианты.
Питер Тейлор

Черт, !='\0'это плохая (хорошая?) Привычка писать код не для гольфа, я позволил этому проникнуть в мои последние два раунда игры в гольф, и в будущем я должен быть более осторожным. Что касается программирования против функции, да, вы абсолютно правы.
Гордон Бейли

@GordonBailey извините за удар, но я сделал несколько изменений в более короткую версию.
oldrinb

2

Python, 66 62 59 58 символов

Вид забавного решения, определенно аккуратная проблема.

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

2

Руби 32 30 28

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

Это вернет MatchDataэкземпляр, если aявляется подпоследовательностью bили nilиным образом.

Старая версия, которая находит подстроку вместо подпоследовательности

Рубин 15

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

Используя String#[](str)метод, который возвращает strif strявляется подстрокой selfи !!возвращает, Booleanесли возвращаемое значение может быть использовано как логическое (и не должно быть trueили false), тогда это может быть только 13 символов:

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

Он вернется, nilесли aне является подстрокой b.


2
Хорошо, но вопрос требует подпоследовательности, а не подстроки.
Гарет

2

SWI-Пролог, SICStus

Встроенный предикат sublist / 2 SICStus проверяет, все ли элементы первого списка также отображаются во втором списке. Этот предикат также доступен в SWI-Prolog через библиотеку совместимости, которая может быть загружена запросом [library(dialect/sicstus/lists)]..

Образец прогона:

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.

Число байтов технически может быть 0, поскольку все, что мы здесь делаем, это запросы, очень похожие на то, как мы запускаем программу и вводим в нее входные данные.


2

PHP, 41 байт

печатает 1 за правду и ничего за ложь

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

Если сделаны только вставки из слова 1 в слово 2, то счетчик равен нулю для истинных случаев

Левенштейн

Попробуйте онлайн!

PHP, 57 байт

печатает 1 для истинного и 0 для ложного

Создает регулярное выражение

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

Попробуйте онлайн!


1
-2 байта: ведение .*не требуется. -2 байт: don't правопреемник $argvв $a. +24 байта: нужны array_map(preg_quote())специальные символы (используйте скобки в качестве разделителей, чтобы избежать второго preg_quoteпараметра.)
Титус

2
@Titus, ведущий. * Необходим для ввода пустой строки, а для ввода я должен обрабатывать только возможно пустую буквенно-цифровую строку с учетом регистра. Вы правы с цитатой, если есть специальные символы. Спасибо за подсчет задания. Скопируйте и вставьте более раннее решение и не думайте об этом
Йорг Хюльсерманн

1
preg_matchне будет жаловаться на пустое регулярное выражение, пока есть разделители. Это будет просто соответствовать чему-либо. Но preg_quote все +22 байт, а не +24: array_map(preg_quote,str_split(...)).
Титус

1
Но тогда входные данные гарантированно будут буквенно-цифровыми :) Но вам по-прежнему не нужна ведущая .*.
Титус

2

Брахилог , 2 байта

⊆ᵈ

Попробуйте онлайн!

Как и с этим ответом, это встроенный предикат, который объявляет отношения между входными и выходными переменными, и является мета-предикатом, который изменяет его, чтобы вместо этого объявить те же отношения между первым и вторым элементами входной переменной (и унифицировать выходная переменная со вторым элементом, но так как это проблема решения, которая здесь не имеет значения). X⊆Yутверждение о том, что X является подпоследовательностью Y, поэтому так и есть [X,Y]⊆ᵈ.

Этот предикат (который, конечно, выводит через успех или неудачу, который печатает true. или false.когда он запускается как программа) принимает входные данные как список из двух строк. Если ввод немного более гибкий ...

Брахилог , 1 байт

Попробуйте онлайн!

Принимает строку X в качестве входной переменной и строку Y в качестве выходной переменной. Выходит через успех или неудачу, как и раньше.При запуске в качестве полной программы X вводится как ввод, а Y - как первый аргумент командной строки.


1

CoffeeScript 73

Вот альтернативный ответ CoffeeScript, использующий регулярные выражения вместо рекурсии:

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

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

Возвращает ложь, когда xиy оба являются пустыми строками. Думаю, нам нужен философ, чтобы сказать нам, является ли пустая строка подпоследовательностью самого себя!

(Опубликовано в качестве отдельного ответа от моего предыдущего, потому что это чувствует себя достаточно по-другому, чтобы оправдать это).


1

PowerShell, 38

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

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


1

Своего рода анти-решение, генерирующее все подпоследовательности 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)]

1

APL (31)

В APL немного не хватает обработки строк.

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

использование:

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

1

Python 132

Похож на Даниеро. Не самое простое решение, но попробовать было весело. Я новичок в Python, поэтому я уверен, что я мог бы сделать его короче, если бы я знал немного больше.

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


1

Питон ( 75 52)

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

Простое рекурсивное решение. В первый раз игра в гольф, так что любые советы о том, как свести это на нет, очень ценятся :)

Проверено со следующим:

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

Спасибо @lirtosiast за некоторые хитрые логические трюки.


1
Вы можете получить это до 52 символов:s=lambda a,b:a==''or b>''and s(a[a[0]==b[0]:],b[1:])
lirtosiast

Спасибо, это умно, используя логическое значение в качестве индекса 0/1 в соединении :)
foslock

1

PHP, 75 65 64 байт

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

принимает входные данные из аргументов командной строки; печатает 1для true, пустая строка для false. Беги с -r.

объяснение:

  • strposвозвращается, falseесли игла $cне находится в стоге сена $argv[2](после положения $p),
    вызывая разрыв цикла.
  • strposтакже возвращается falseза пустой иглой, разрывая петлю в конце $argv[1].
  • Если $argv[1]это подпоследовательность $argv[2],$c будет пустым, когда цикл прерывается.
  • strposНеобходимо @подавить Empty needleпредупреждение.

+$pвместо $p+1этого нет необходимости подчеркивать
Йорг Хюльсерманн

@ JörgHülsermann +1необходим для продвижения в стоге сена; и подчеркивание избегает $p=-1инициализации. Но ... я могу избежать false!==.
Титус

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.