A string x
generates a string y
if y
is a substring of an infinite repeat of x
. For example abc
generates bcabcab
.
Write a program to find the shortest, lexicographically smallest string that will generate the input. You are given on standard input a single line of text. You should print the generating string to standard output. For example:
input
bcabcabca
output
abc
Shortest code wins. You may assume the input contains only the characters a-z (and a trailing newline if you want).
9 Answers 9
Ruby 1.9, 40 characters
gets;a=?a;a.next!until(a*~/$/)[$_];$><<a
Assumes the input is not terminated by a newline. Also it's probably ridiculously slow for larger results.
$ echo -n "bcabcabca" | ruby genlex.rb
abc
$ echo -n "barfoobarfoobarfoo" | ruby1.9 genlex.rb
arfoob
Python (削除) 88 (削除ここまで) 185 chars
import re
s=raw_input()
m=s.index(min(s))
s=s[m:]+s[:m]
i=0
while s.replace(s[:i],''):i+=1
m=min(s[:i])
s=re.findall('%s[\w]*?(?=%s|$)'%(m,m),s[:i])
m=s.index(min(s))
print ''.join(s[m:]+s[:m])
Output:
bcabcabca
abc
aaa
a
abc
abc
cccbbcccbbcccbb
bbccc
barfoofoobarfoofoo
arfoofoob
bacabac
abacbac
-
\$\begingroup\$ Doesn't give you the lexicographically smallest string for some inputs, e.g. "bacabac" \$\endgroup\$Howard– Howard2011年06月16日 03:23:41 +00:00Commented Jun 16, 2011 at 3:23
-
\$\begingroup\$ @Howard You are right. I've updated my code, it is much longer now, but handles strings like
bacabac
correctly. \$\endgroup\$Vader– Vader2011年06月16日 22:24:14 +00:00Commented Jun 16, 2011 at 22:24 -
\$\begingroup\$ "abac" would be correct, see @yogsototh's answer: abacabacabac. \$\endgroup\$Howard– Howard2011年06月17日 05:02:45 +00:00Commented Jun 17, 2011 at 5:02
Haskell, (削除) 299 (削除ここまで) 128 characters
import Data.List
main=interact(\z->minimum$filter(\w->isInfixOf z$concat$replicate(length z)w) $filter((/=)"")$inits=<<tails z)
Thanks to jloy! Now the version is both far shorter and I believe correct.
-
1\$\begingroup\$ So, the good news is that it's possible to golf this solution down to about 91 chars if you accept input on stdin as in Ventero's Ruby solution. Unfortunately, the input
cabcabcabc
producesabcabc
, so this solution isn't quite there. I think you'll need to modifyq++q++q
in order to get the desired result. My quick attempt at fixing bumped things back up to 145 chars though. (Spoilers are here: gist.github.com/1035161) \$\endgroup\$user1011– user10112011年06月20日 05:14:08 +00:00Commented Jun 20, 2011 at 5:14 -
\$\begingroup\$ Thanks! I didn't knew about interact nor never though about inits <<= tails to get all substrings. I slightly modified your version to gain a bit of characters. I removed sort and changed filter(not.null) by filter((/=)""). Thanks again! \$\endgroup\$yogsototh– yogsototh2011年06月20日 12:01:59 +00:00Commented Jun 20, 2011 at 12:01
-
\$\begingroup\$ Why do you need
(/=)""
condition? It doesn't seem to do anything. Also, getting rid of lambdas helps: you can get rid of w altogether using.
operator and change main function tomain=interact s
to save a couple of characters. \$\endgroup\$Rotsor– Rotsor2011年06月21日 15:06:12 +00:00Commented Jun 21, 2011 at 15:06 -
\$\begingroup\$ I think the answer for "bca" is wrong. It should be "abc", but is "bca" now. \$\endgroup\$Rotsor– Rotsor2011年06月21日 15:14:26 +00:00Commented Jun 21, 2011 at 15:14
-
\$\begingroup\$ One possible solution is to use
permutations
instead oftails
. \$\endgroup\$Rotsor– Rotsor2011年06月21日 15:25:38 +00:00Commented Jun 21, 2011 at 15:25
Python, (削除) 121 (削除ここまで) (削除) 137 (削除ここまで) 129 chars
s=raw_input()
n=len(s)
l=[(s+s)[i/n:i/n+i%n+1]for i in range(n*n)]
print min(filter(lambda x:(x*len(s)).find(s)+1,sorted(l)),key=len)
EDIT: fixed the bug spotted by JiminP
-
\$\begingroup\$ Wow, it's great! Unfortunately, it prints
aabab
for stringababa
... :( \$\endgroup\$JiminP– JiminP2011年06月23日 14:52:34 +00:00Commented Jun 23, 2011 at 14:52 -
\$\begingroup\$ Ok, fixed... it's getting longer :( \$\endgroup\$Jules Olléon– Jules Olléon2011年06月23日 16:04:07 +00:00Commented Jun 23, 2011 at 16:04
Ruby 1.9, 36
$><<(?a..gets).find{|s|(s*~/$/)[$_]}
Uses the same approach as Ventero's solution.
Python, (削除) 161 159 166 140 141 134 (削除ここまで) 132 chars
y=raw_input();i=n=l=len(y)
while i:
if (y[:i]*l)[:l]==y:n=i
i-=1
x=y[:n];y=x*2
while i<n:
x=min(x,y[i:i+n])
i+=1
print x
EDIT : Golfed the code after reading Jules Olléon's comment. Removed a 'bug' that bcdabcdab
results in abbc
.
EDIT2 : Fixed the bug (abaa
results in aaa
) spotted by Jules Olléon.
I don't know about Python well, so this code is probably 'not golfed'.
I love this rule:
You may assume the input contains only the characters a-z...
Inputs & Outputs
bcdabcd
abcd
bcabcabca
abc
abcdabcd
abcd
bcdabcdab
abcd
barfoofoobarfoofoobar
arfoofoob
cccbbcccbbcccbb
bbccc
aaaaaaaaaaaaaaaa
a
thequickbrownfox
brownfoxthequick
ababa
ab
abaa
aab
-
1\$\begingroup\$ Brown fox, the quick! Dog, the lazy! \$\endgroup\$JiminP– JiminP2011年06月20日 13:04:00 +00:00Commented Jun 20, 2011 at 13:04
-
\$\begingroup\$ Nice solution, pretty short and probably the best complexity here! You could golf it a bit - for instance, you dont need "int" to compare strings; and replace "while i>0" by "while i" and "y=y+y" by "y*=2". \$\endgroup\$Jules Olléon– Jules Olléon2011年06月23日 14:27:18 +00:00Commented Jun 23, 2011 at 14:27
-
\$\begingroup\$ Actually there's a problem : for abaa it prints aaa... \$\endgroup\$Jules Olléon– Jules Olléon2011年06月23日 16:09:51 +00:00Commented Jun 23, 2011 at 16:09
-
\$\begingroup\$ @Jules Thanks for the comment! I didn't think about that one... \$\endgroup\$JiminP– JiminP2011年06月23日 16:18:07 +00:00Commented Jun 23, 2011 at 16:18
-
\$\begingroup\$ You can do
i-=1
instead ofi=i-1
. Likewise for the increment. \$\endgroup\$Lowjacker– Lowjacker2011年06月26日 11:13:00 +00:00Commented Jun 26, 2011 at 11:13
Mathematica 124 bytes
x = StringLength@(y = "");
For[i = 1, ! (s = y~StringTake~i)~StringRepeat~x~StringContainsQ~y,i++];
First@Sort@StringPartition[s <> s, i, 1]
Whitespace and newlines (in the presence of semicolons at the ends of lines) have no meaning in Mathematica and are included here for readability.
Input goes in between the quotation marks in the first line. If recast as a function, that takes string input like so:
f=(x=StringLength@(y=#);For[i=1,!(s=y~StringTake~i)~StringRepeat~x~StringContainsQ~y,i++];First@Sort@StringPartition[s<>s,i,1])&
f@"bca"
(* "abc" *)
f@"abaa"
(* "aab" *)
then it's 128 bytes.
The For
loop takes the first i
characters of the input and repeats them at least up to the length of the input, then checks if the input is a substring of the result. Having found the length of the period of the string, the StringPartition
command concatenates two copies of that period and takes all substrings of that length from it (basically gets all cyclic permutations), then First@Sort
finds the first one of them when lexicographically ordered.
-
1\$\begingroup\$ This doesn't seem to work. Given input
abacaba
it givesabc
, which could never generate the input... \$\endgroup\$thejonymyster– thejonymyster2022年11月01日 02:34:17 +00:00Commented Nov 1, 2022 at 2:34
javascript 96 Chars.
var temp = {},len = str.length;
for(i in str)
temp[str[i]] = true;
Object.keys(temp).join("");
-
1\$\begingroup\$ Welcome to the community ! I couldn't test your code though, could you provide either code reading from GET/POST and writing with alert or console.log or a function taking the input as a parameter and returning the output? \$\endgroup\$Aaron– Aaron2015年10月20日 09:02:46 +00:00Commented Oct 20, 2015 at 9:02
-
\$\begingroup\$ @AaronGOUZIT added pluckr \$\endgroup\$ngLover– ngLover2015年10月20日 11:48:52 +00:00Commented Oct 20, 2015 at 11:48
-
\$\begingroup\$ Thanks, that helps. Still, the code you posted can't be used alone, so that cheats the byte count. More importantly, I'm afraid your code doesn't respect the specs : I believe you return a set of unique letters used rather than a "generating string", which we should be able to repeat (as a whole) with optional truncation to obtain the input. I'm looking forward to seeing your updated code ! \$\endgroup\$Aaron– Aaron2015年10月20日 12:31:52 +00:00Commented Oct 20, 2015 at 12:31
Explore related questions
See similar questions with these tags.
bac
in your example rather thanabc
? \$\endgroup\$bac
s. \$\endgroup\$(bca)^n
, which meansbca
is just as valid for the given example asabc
. \$\endgroup\$bca
is not the smallest lexicographically. \$\endgroup\$