Проверьте, является ли строка тасовкой близнецов


10

объяснение

Две строки можно перетасовать, переставляя их буквы, чтобы сформировать новую строку, так же как две стопки карт можно перетасовать, чтобы сформировать одну стопку.

Например, строки HELLOи WORLDмогут быть перемешаны, чтобы сформировать HWEOLRLLOD, или HEWORLLLDO, или, возможно, просто HELLOWORLD.

Это не случайный порядок, если исходный порядок букв не сохранен. Например, Din WORLDне может появиться раньше Rпосле перетасовки. Это означает, что EHLLOWRDLO, например, это не случайный случай, HELLOи WORLD, хотя он содержит все оригинальные буквы.

Строка - это тасовка близнецов, если она может быть образована путем тасования двух одинаковых струн. Например, ABACBDECDEэто тасование близнецов, потому что оно может быть сформировано путем тасования ABCDEи ABCDE. DBEACBCADEэто не тасовка близнецов, потому что она не может быть сформирована путем тасования двух одинаковых строк.

Детали программы

Если задана входная строка, выведите, 0если она не является случайным образом двойников, и выведите одну из строк двойников, если это случайный случай двойников.

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

Это код гольф, поэтому выигрывает самое короткое решение.

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

> ABACBDECDE
ABCDE

> DBEACBCADE
0

> FFFFFF
FFF

> FFGGG
0

> ABBA
0

> AABB
AB

> AABAAB
AAB

У меня есть пример (не в гольф) реализации .


Пример строки FGG нарушает утверждение that the input string has a length inclusively between four and twenty charactersи не говорит мне «никогда не доверяйте вводу пользователя!», «Никогда не доверяйте спецификациям!»
пользователь неизвестен

@userunknown Это так неловко! Я отредактировал это, FFGGGчтобы сделать это последовательным.
Питер Олсон

1
Любопытно, может кто-нибудь придумать решение с субэкспоненциальной сложностью наихудшего случая или доказать, что его нет?
Илмари Каронен

Ответы:


4

Хаскелл, 114

main=getLine>>=putStrLn.f.p;f x=head$[a|(a,b)<-x,a==b]++["0"]
p[]=[([],[])];p(x:y)=do(a,b)<-p y;[(x:a,b),(a,x:b)]

Ungolfed:

main :: IO ()
main = getLine >>= putStrLn . findMatch . partitions

-- | Find the first partition where the two subsequences are
-- equal. If none are, return "0".
findMatch :: [(String, String)] -> String
findMatch ps = head $ [a | (a,b) <- ps, a == b] ++ ["0"]

-- | Return all possible partitions of the input into two
-- subsequences. Preserves the order of each subsequence.
--
-- Example:
-- partitions "AB" == [("AB",""),("B","A"),("A","B"),("","AB")]
partitions :: [a] -> [([a], [a])]
partitions []     = [([], [])]
partitions (x:xs) = do (a, b) <- partitions xs
                       [(x:a, b), (a, x:b)]

Объяснение:

Большая часть работы выполняется в partitionsфункции. Он работает путем рекурсивного генерирования всех разделов (a, b)хвоста списка, а затем с помощью монады списка, чтобы добавить начальный элемент xк каждому из них и собрать все результаты.

findMatchработает путем фильтрации этого списка, так что остаются только разделы, в которых подпоследовательности равны. Затем он возвращает первую подпоследовательность в первом разделе. Если ничего не осталось, список пуст, поэтому "0"вместо него возвращается добавленный в конце.

main просто читает ввод, передает его через эти две функции и печатает его.


Для тех из нас, кто не умеет читать на Хаскеле, вы дадите объяснение?
Mr.Wizard

1
@ Mr.Wizard: см. Редактировать.
Хаммар

Я думаю, что придумал что-то довольно похожее, хотя и не такое короткое, но я добавил глупость, которая сделала его полным провалом. Вы не возражаете, если я реализую этот алгоритм в Mathematica?
Mr.Wizard

4

R, 113 символов

l=length(x<-charToRaw(scan(,'')));max(apply(combn(l,l/2),2,function(i)if(all(x[i]==x[-i]))rawToChar(x[i])else 0))

Ungolfed (и вместо этого функция, которая принимает строку):

untwin <- function(x) {
  x <- charToRaw(x)
  indMtx <- combn(length(x),length(x)/2)
  res <- apply(indMtx, 2, function(i) {
    if (all(x[i]==x[-i]))
      rawToChar(x[i])
    else
      0
  })
  max(res)
}

untwin("ABACBDECDE") # "ABCDE"
untwin("DBEACBCADE") # 0

Решение опирается на combnфункцию, которая генерирует все комбинации индексов в виде столбцов в матрице. applyзатем применяет функцию к каждому столбцу (измерению 2) в матрице и возвращает вектор строк или нулей. maxзатем найдите самую большую строку (которая превосходит 0).

Крутой особенностью в R является возможность выбрать подмножество вектора с заданным вектором индексов, а затем выбрать дополнение к этому подмножеству путем отрицания индексов:x[i] == x[-i]


Сделано несколько дополнительных улучшений и уменьшено количество символов.
Томми

3

Математика, 87

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

<<Combinatorica`

f=Catch[Cases[Characters@#~KSetPartitions~2,{x_,x_}:>Throw[""<>x]];0]&

Тестовое задание:

f /@ {"ABACBDECDE", "DBEACBCADE", "FFFFFF", "FGG", "ABBA", "AABB", "AABAAB"}
{"ABCDE", 0, "FFF", 0, 0, "AB", "AAB"}

1

D

string c(string in,string a=[],string b=[]){
    if(in.length==0)return a==b?a;"0";
    auto r=c(in[1..$],a~in[0],b);
    return r=="0"?c(in[1..$],a,b~in[0]):r;
}
void main(){writeln(c(readline));}

используя глубину сначала рекурсивный поиск

Я могу сделать это быстрее с int i = min(a.length,b.length);if(a[0..i]!=b[0..i])return "0";оговоркой


На IDEONE я не смог запустить программу с void main(){writeln(c("ABCADABCAD"));}- просто другая версия D, моя ошибка, что-то еще? Что насчет "ABCABCA"?
пользователь неизвестен

вам нужно будет импортировать std.stdio; для IO
фрик с трещоткой

1

Рубин, 89 знаков

s=->a,x,y{a=="\n"?x==y ?x:?0:[s[b=a[1..-1],x+c=a[0],y],s[b,x,y+c]].max}
$><<s[gets,'','']

Этот код реализует простой рекурсивный алгоритм поиска. Ввод должен быть дан на STDIN.


1

Perl, 68 символов

/^((.+)(?{local($x,$,)=($,,$x.$^N)}))+$(?(?{$o=$,eq$x&&$,})|x)/?$o:0

Предполагается, что входная строка находится в $_переменной, а выход является значением выражения. Конечные переводы строк при вводе игнорируются. Вы можете запустить это из командной строки следующим образом:

perl -lne 'print /^((.+)(?{local($x,$,)=($,,$x.$^N)}))+$(?(?{$o=$,eq$x&&$,})|x)/?$o:0'

Этот код использует движок регулярных выражений Perl (и, в частности, его встроенную функцию выполнения кода ) для возврата. По сути, он сопоставляет входную строку с регулярным выражением ^((.+))+$, отслеживая нечетные и четные подспряжения в $xи $,и отклоняя совпадение в конце, если они не равны.


Это имеет правильный результат для AABAAB?
Питер Олсон

Да, это так. (На самом деле, AABAABэто простое решение для этого решения, поскольку внешняя группа должна совпадать только дважды. Мне потребовалось гораздо больше времени, чтобы AABBправильно ее обработать .)
Ilmari Karonen

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