最长的非重复子串


33

给定一个字符串作为输入,请找到没有两次或两次以上任何字符的最长连续子字符串。如果有多个这样的子字符串,则可以输出。如果需要,您可以假定输入在可打印的ASCII范围内。

计分

答案将首先按其自身最长的非重复子字符串的长度排序,然后按其总长度排序。对于这两个标准,较低的分数会更好。根据语言的不同,这可能会感觉像是带有源代码限制的挑战。

琐事

在某些语言中,得分为1(x)或2(x)(脑筋和其他图腾焦油)非常容易,但是在其他语言中,最小化最长的非重复子字符串是一个挑战。在Haskell中获得2分很开心,因此,我鼓励您寻找有趣的语言。

测试用例

"Good morning, Green orb!" -> "ing, Gre"
"fffffffffff" -> "f"
"oiiiiioiiii" -> "io", "oi"
"1234567890"  -> "1234567890"
"11122324455" -> "324"

计分提交

您可以使用以下代码片段为程序评分:


建议的测试用例:11122324455Jonathan Allan意识到我的第一个修订版没有正确处理它。
丹尼斯,

@Dennis添加了测试用例。我很好奇这是怎么发生的。
小麦巫师

2
我生成了所有子字符串(已经按长度排序),然后对子字符串进行了重复数据删除,并保留了那些仍为子字符串的字符串。不幸的是,这改变了顺序。11122在之后发生324,但重复数据删除到12
丹尼斯,

我想知道空白答案在哪里。
魔术章鱼缸

Answers:


13

C,得分2, 747个   720  662字节

L  [  1  <<  7  ]  ,  *  q  ,  *  r  ,  l  ,  d  ,  i  ,  c  ,  j  ,  s  ,  t  ,  k  =  1  <<  7  ;  h  (  )  {  q  =  s  +  i  +  j  ++  ;  *  q  %  k  &&  !  L  [  *  q  %  k  ]  ++  &&  h  (  ++  c  )  ;  }  g  (  )  {  q  =  s  +  i  ;  *  q  %  k  ?  z  (  k  )  ,  h  (  j  =  c  =  0  )  ,  c  >  d  &&  (  d  =  c  )  &&  (  l  =  i  )  ,  g  (  ++  i  )  :  0  ;  }  f  (  S  ,  T  )  {  s  =  S  ;  l  =  i  =  d  =  0  ;  g  (  t  =  T  )  ;  p  (  i  =  0  )  ;  }  p  (  )  {  q  =  s  +  l  +  i  ;  r  =  t  +  i  ;  i  ++  <  d  ?  p  (  *  r  =  *  q  )  :  (  *  r  =  0  )  ;  }  z  (  i  )  {  L  [  --  i  ]  =  0  ;  i  &&  z  (  i  )  ;  }

至少可在32位MinGW上运行(禁用优化)。不使用单个关键字。

显然也可以与gcc和clang一起在TIO上工作:在线尝试!(感谢@Dennis!)

致电:

int main()
{
    char str[1024];

    f("Good morning, Green orb!", str);
    puts(str);

    f("fffffffffff", str);
    puts(str);

    f("oiiiiioiiii", str);
    puts(str);

    f("1234567890", str);
    puts(str);

    f("L  [  1  <<  7  ]  ,  *  q  ,  *  r  ,  l  ,  d  ,  i  ,  c  ,  j  ,  s  ,  t  ,  k  =  1  <<  7  ;  h  (  )  {  q  =  s  +  i  +  j  ++  ;  *  q  %  k  &&  !  L  [  *  q  %  k  ]  ++  &&  h  (  ++  c  )  ;  }  g  (  )  {  q  =  s  +  i  ;  *  q  %  k  ?  z  (  k  )  ,  h  (  j  =  c  =  0  )  ,  c  >  d  &&  (  d  =  c  )  &&  (  l  =  i  )  ,  g  (  ++  i  )  :  0  ;  }  f  (  S  ,  T  )  {  s  =  S  ;  l  =  i  =  d  =  0  ;  g  (  t  =  T  )  ;  p  (  i  =  0  )  ;  }  p  (  )  {  q  =  s  +  l  +  i  ;  r  =  t  +  i  ;  i  ++  <  d  ?  p  (  *  r  =  *  q  )  :  (  *  r  =  0  )  ;  }  z  (  i  )  {  L  [  --  i  ]  =  0  ;  i  &&  z  (  i  )  ;  }");
    puts(str);
}

输出:

格式更具可读性的代码:

L[1<<7],
*q, *r, l, d, i, c, j, s, t, k=1<<7;

h()
{
    q = s+i+j++;
    *q%k && !L[*q%k]++ && h(++c);
}

g()
{
    q = s+i;
    *q%k ? z(k), h(j=c=0), c>d && (d=c) && (l=i), g(++i) : 0;
}

f(S, T)
{
    s = S;
    l = i = d = 0;
    g(t=T);
    p(i=0);
}

p()
{
    q = s+l+i;
    r = t+i;
    i++<d ? p(*r=*q) : (*r=0);
}

z(i)
{
    L[--i] = 0;
    i && z(i);
}

这可用于生成适当的间距,以得到分数2的格式:在线尝试!


C,得分3,309个字节

i
,
j
,
l
,
c
,
d
;
f
(
\
c\
\
h\
\
a\
\
r
*
s
)
{
\
f\
\
o\
\
r
\
(
i
=
l
=
d
=
0
;
s
[
i
]
;
c
>
d
&&
(
d
=
c
)
&&
(
l
=
i
)
,
++
i
)
\
f\
\
o\
\
r
(
\
c\
\
h\
\
a\
\
r

L
[
\
1\
\
2\
\
8
\
]
=
{
j
=
c
=
0
}
;
s
[
i
+
j
]
&&
!
L
[
s
[
i
+
j
++
]
]
++
;
++
c
)
;
\
w\
\
r\
\
i\
\
t\
\
e
(
1
,
s
+
l
,
d
)
;
}

在线尝试!


10

Haskell中,2分,492个 ... 307个 224 212 209 207字节

((yy:yyy))??ss|ss==yy  =  ""  |  yy==yy=yy:yyy??ss
ss??sss=ss
ss""=""

ss((ff:fff))  =  ff  :  ss  fff??ff
ff""=""

ff((xxx:xx))  =  ss((xxx:xx))##ff  xx
xx##xxx  |  ((((xx>>xx))<))  $  xxx>>xx=xxx|xx==xx=xx

在线尝试!

从字面上Golfed数百字节感谢到WW与Orjan约翰森

说明

该函数(??)接受一个字符c和一个字符串,s并返回s不包含的最长前缀c。松懈且未针对得分进行优化:

c ?? (y:s)  
    | c==y = ""
    | True = y : c ?? s
c ?? s = s

该函数ss用于(??)查找给定字符串的唯一字符的最长前缀:

ss (x:r) = x : (x ?? ss r)
ss "" = ""

(##)是一个需要两个字符串并返回较长字符串的函数。的长度相比的工作原理是重复串x尽可能经常x是长(x>>y如)和y长(y>>x),并检查将所得的字符串按字典顺序变大。

x ## y
  | (x>>x) < (y>>x) = y
  | True = x

最后ff递归输入字符串,使用生成最长的前缀ss,递归确定字符串尾部的最长的非重复子字符串,并使用以下命令返回两者中的较长者(##)

ff "" = ""
ff (x:r) = ss(x:r) ## ff r

4
224,主要是通过融合中间列表。
与Orjan约翰森

2
我将此答案与我之前在聊天室中发布的答案结合在一起,得到216
小麦巫师

3
209通过重新排序。
与Orjan约翰森

3
随着赏金公布我又看,实现了@招居然花费2个字节以上只是让?2个字符:207
与Orjan约翰森

5

Lua,得分3,274字节

g='g'..'s'..'u'..'b'  _G  [  'l'..'o'..'a'..'d'  ](  g[g  ](  "s  =...f  o  r d = # s - 1 , 0 , - 1 d  o f  or r = 1 , # s - d d  o t = s :s  ub  (r  ,r  +d  )i  f n  ot t:  fi  nd  '(  .)  .*  %1  't  he  n p  ri  nt  (t  )r  et  ur  n en  d e  n  d e  nd  ","  ",""))(...)

注意:需要Lua 5.2或Lua 5.3

用法:

$ lua lnrs.lua "Good morning, Green orb!"
ing, Gre
$ lua lnrs.lua "fffffffffff"
f
$ lua lnrs.lua "oiiiiioiiii"
oi
$ lua lnrs.lua "1234567890"
1234567890
$ lua lnrs.lua "11122324455"
324

主要思想:将所有内容与空格交织,插入" "(两个空格)以拆分长标识符

取消程式码:

g = "gsub"
_G["load"](
   g[g](      -- g[g] == string.gsub - a function for substitution of substrings
      "The source of actual program, but two-space sequences were inserted in some places", 
      "  ",   -- we are replacing all two-space substrings
      ""      -- with an empty string
   )
)(...)

实际程序(删除所有对空格后):

s = ...
for d = #s - 1, 0, -1 do
   for r = 1, #s - d do
      t = s:sub(r, r+d)
      if not t:find"(.).*%1" then
         print(t)
         return
      end
   end
end

顺便说一句,我的代码无法计算分数的JS代码段。


4

视网膜0.8.2,37字节,得分9

.
$&$'¶
(.)(?<=\1.+).*

O#$^`
$.&
1G`

在线尝试!将此答案直接翻译为Retina 1可使用N代替保存一个字节O#。但是,如果您天真地对Retina 1高尔夫球打低到28个字节,那么它的分数实际上会上升到10!说明:

.
$&$'¶

生成输入的所有后缀。

(.)(?<=\1.+).*

对于每个后缀,请使用前缀直至第一个重复的字符。

O#$^`
$.&

按长度的相反顺序(即最长的优先)对其余字符串进行排序。

1G`

取最长的。


4

果冻,得分2,14字节

Ẇµµff  Q  €  Ṫ

感谢@JonathanAllan获得-1分,+ 7个字节并注意到一个错误。

在线尝试!

怎么运行的

Ẇµµff  Q  €  Ṫ  Main link. Argument: s (string)

Ẇ               Window; yield all substrings of s, sorted by length.
 µ              Begin a new chain. Argument: A (array of substrings)
  µ             Begin a new chain. Argument: A (array of substrings)
   f            Filter A by presence in itself. Does nothing.
       Q  €     Unique each; deduplicate all strings in A.
    f           Filter A by presence in the array of deduplicated substrings,
                keeping only substrings composed of unique characters.
             Ṫ  Tail; take the last (longest) kept substring.

4

干净,得分7 5,276字节

@[ss:s]=rr(pp[][ss:s])((@s))
@s=s
ee x[rr:xx]|e x rr=True=ee x xx
ee x xx=f
f=e'e'' '
e::!  Char  !  Char  ->Bool
e  _ _=  code  {

eqC
}
pp p[r:rr]|ee r p=p=pp(a r p)rr
pp a _=a
a  x[ll:l]=[ll:a x  l]
a l ll=[l]
l[]rr=e'l''l'
l ff[]=f

l[r:rr][ss:ll]=l rr ll
rr x y|l x y=y=x

在线尝试!感谢@Οurous向我展示了可以直接从Clean内调用ABC机器代码。这样可以摆脱以前的瓶颈import,该瓶颈将最小分数设置为7,但是需要使用关键字code将最小分数设置为5 的关键字。

您可以在此处找到以上代码的原始版本,而不是分数优化版本:在线尝试!


以前的版本,其具有得分7,158个 154 130字节

import  StdEnv  
@[xx:rr]=c(%[][xx:rr])(@rr)
@e=e
c s b|  length  s<  length  b=b=s
%s[xx:r]|  isMember xx s=s= %(s++[xx])r
%r _=r

在线尝试!

随着import分数不能低于7.在不导入一个需要实现对字符串或字符平等,不受任何库函数这可能不是可能的,因为可以在新版本上面可以看到。


1
实际上,您可以使用内联ABC实现平等,这会降低分数。如果您有兴趣,我会在今天晚些时候再提出建议的修改。
世纪

例如:字符相等:tio.run
##

@ourous A code block with raw ABC instructions, which can be used for primitive functions like integer addition, for linking with C, bypassing the type system... welcome down the rabbit hole!来自cloogle)当然听起来很诱人。明天我会仔细研究,谢谢您的建议!
Laikoni '18

1
@Οurous再次感谢您,通过您的char相等性测试,现在的分数是
5。– Laikoni

顺便说一句,您不需要任何一个-IL标志,因为什么也没有导入。
世纪

3

Python 3,得分4,155字节

exec(('l=la''mbd''a f'',e=en''ume''rat''e:m''ax''([f[ j  :k]  for  j,i in e ( f)f''or  k,i in e ( f )if  len  ( { *''f[j'':k]''})==k-''j],''key''=le''n)'))

这定义了一个功能l

感谢@xnor指出长度为3的字符串不会提高得分,节省了32个字节。

在线尝试!


字符串可以是3个块,对吗?
xnor

@xnor确实更改了函数的名称。谢谢!
丹尼斯,

3

Brachylog,得分2,19字节

s  ᶠ  l  ᵒ  ≠  ˢ  t

在线尝试!

只是一个无聊的旧“空间一切都掉了”的答案。至少我了解到,元谓词可以与谓词隔开,并且仍然可以工作((参数)下标和上标不能)。

s ᶠ -查找给定字符串的所有子字符串

l ᵒ -按长度排序(默认情况下升序)

≠ ˢ -选择具有所有不同元素的元素

t -得到它的尾部(最后一个元素)-长度最大的那个


2

Pyth,11个字节,得分4

-4分感谢Dennis

e lD {I# .:

elD{I#.:Q      Full program, inputs "string" from stdin and outputs to stdout
e              The last element of the list generated by taking
      .:Q      All substrings of the input
     #         Filtered for
   {I          Being invariant over deduplicate i.e. being "non-repeating"
 lD            and sorted by length

在线尝试!


2

外壳,得分2,10个字节

►IIËII≠IIQ

在线尝试!

说明

该程序等效于此:

►Ë≠Q  Implicit input.
   Q  List of substrings.
►     Find one that maximizes:
 Ë    all ordered pairs
  ≠   are inequal.

内建函数会对其参数的所有有序对Ë进行求值,如果每个结果均为真,则返回,否则返回。当我们最大化它时,我们发现没有重复字符的最长字符串。xlength(x)+10

在提交中,我只是I在每个函数之间插入了identity函数两次。由于与相同Ë,所以与等等I≠相同,因此这不会更改语义。唯一的危险是高阶函数可以决定使用Is作为其参数,但幸运的是,这会导致程序中出现类型错误,因此不会发生。


2

Clojure,得分4

#(  let  [N  (fn  [[_ & r]] r) R  (fn  R [f v c]  (if  c (R f (f v (  nth  c 0))  ( N  c)) v)) C  (fn  C  (  [i]  (C (  seq  i) 0)) ( [i  n]  (if i (C ( N  i )  (  inc n)) n)))  J  (fn  [c  i]  (assoc c (C  c) i)) I  (fn  F [f i n R]  (if ( =  (C  R) n) R (F f (f  i) n ( J  R (f  i)))))] ( apply  str  (R ( fn  [a  b] ( if  (< (C  a)  (C  b)) b a )) "" (  for  [k  (I N % (C  % ) [])]  (R  ( fn [ t  c ] ( if ( or ( = t (  str t) ) ((  set t)c))(apply  str t) ( J  t c)))[]k)))))

噢,天哪,这很痛苦!N实现nextRis reduceCis countJis conj(仅适用于向量)和Iis iterateapply str有两次,因为否则“ aaaa”输入将不会返回字符串而是一个向量[\a]。幸运的是,我必须使用applyassoc,但我不知道您可以将一个索引附加到向量的最后一个元素之外:o


我节省了一些空间:在线试用!
与Orjan约翰森


1

Python 3,得分4,317字节

exec(('%s'  *58  %(  's=','in','pu','t(',');','pr','in','t(','so','rt','ed','((s','[i',':j',']f','or',' j',' i','n ','ra','ng','e(','1,','le','n(','s)','+1',')f','or',' i',' i','n ','ra','ng','e(','j)','if',' l','en','(s','et','(s','[i',':j',']))','==l','en','(s','[i',':j',']))',',k','ey','=l','en',')[','-1','])')))

在线尝试!

未执行的代码:

s=input();print(sorted((s[i:j]for j in range(1,len(s)+1)for i in range(j)if len(set(s[i:j]))==len(s[i:j])),key=len)[-1])

lambda a包含mbda 得分为5的功能return,显然不能满足其功能需求exec(因此得分至少为5 eturn),因此需要一个完整的程序。可能会降低未执行代码的大小,但我看不出有任何明显的改进。


1

爱丽丝,40字节

/ii..nn$$@@BBww..DD~~FF..!!nn$$KK??oo@@

(尾随换行符)

在线尝试!

指令指针在顺序模式下沿对角线移动,因此仅执行其他所有字符。

i.n$@Bw.D~F.!n$K?o@

i     take input
.n$@  terminate if empty
B     push all nonempty substrings, with the longest on the top of the stack
w     push return address (start main loop)
.     make copy of current substring
D     deduplicate characters
~     swap: this places the original above the deduplicated copy
F     Push the original string if it is a substring of the deduplicated copy
      (which can only happen if they're equal); otherwise push empty string
.!    place a copy on the tape
n$K   if the empty string was pushed, return to start of loop
o     output
@     terminate

1

Perl 6,得分:15 10 8,长度:46 55 62字节

{~m:ov/(.+)<!{$0.comb.repeated}>/.max(&chars)}

测试一下

{~m:ov/(..*)<!{(($0)).comb.repeated}>{{}}/.max(&chars)}

测试一下

{m:ov:i/(..*)<!{(($0)).comb.repeated}>{{}}/.max((&chars)).Str}

测试一下

展开:

{    # bare block lambda with implicit parameter 「$_」

    m                          # match (implicitly against 「$_」)
    :overlap                   # in every single way possible
    :ignorecase                # add a 「:」 to break up substring
    /

      (..*)                    # match at least one character

      <!{
        (($0)).comb.repeated  # backtrack if there were repeats
      }>

      {{}}                    # anon hash in code block (no-op)
    /

    .max((&chars))            # get the longest

    .Str                      # coerce to a Str (from a Match object)
}

88字节的5分。不过可能会有一些地方可以打高尔夫球
乔·金

1

Java 8,得分9(384 B) 7(401 B)

S -> { int s = 0 , e = 0 , l = 0 , x = 0 , y = 0 , b [ ] = new int [ 256 ] ; for ( ; x <S.  length  & y <S.  length  & l <S.  length  - x ; x ++ ) { b [S[x]] = 1 ; for ( y ++ ; y <S.  length  && b [S[y]] < 1 ; b [S[y ++]] = 1 ) ; if ( l < y - x ) { s = x ; e = y ; l = y - x ; } for ( ; y <S.  length  && x < y & S[x] != S[y  ];)b [S[x ++]] = 0 ; }  String g=""; for( ; s<e ; g+= S[s++]);  return  g;}
  • 初始版本。从这里下去。由于的得分是9 "ubstring ",因此substring将是第一部分替换。
  • 由于" length",现在的得分是7 ,我可能无法进一步降低它。我怀疑是否可以删除的四种用法length。如果有可能," eturn"(6)可能会将分数降低1作为最终的改进,但我想是这样(除非字节数可能有一点减少。)

在线尝试。



0

Mathematica,得分11 9

Length@Last@Select[Subsequences[Characters@#],#==DeleteDuplicates  @#&]&

通过遮盖函数名称,将最长的非重复字符串减少几个字节:

Length@Last@Select[Subsequences[Characters  @#],#==(  ToExpression@ 
StringJoin@@FromCharacterCode@{{68},{101},{108},{101},{116},{101},{68},{117},
{112},{108},{105},{99},{97},{116},{101},{115}}))@#&]&

0

科特林,评分:11 10 9个字节,长度:227个 246 245字节

indices
  .flatMap { p -> indices . map { p to p + it } }
  .  filter { (r,i) -> i < length  }
  .map { ( s , a )->substring  (  s,  a  ) }
  .  filter { it  .  groupBy  { it } .  none { ( k , v )->v . size>1 } }
  .maxBy { it.length }

最长为ubstring,即9个字符

它的名称如下:

val c = "Good morning, Green orb!"

fun String.c(): String? = indices
    .flatMap { p -> indices . map { p to p + it } }
    .  filter { (r,i) -> i < length  }
    .map { ( s , a )->substring  (  s,  a  ) }
    .  filter { it  .  groupBy  { it } .  none { ( k , v )->v . size>1 } }
    .maxBy { it.length }

fun main(args: Array<String>) {
    val text = """indices
    .flatMap { p -> indices . map { p to p + it } }
    .  filter { (r,i) -> i < length  }
    .map { ( s , a )->substring  (  s,  a  ) }
    .  filter { it  .  groupBy  { it } .  none { ( k , v )->v . size>1 } }
    .maxBy { it.length }"""
    val message = text.c()!!
    println(message)
    println(text.length)
    println(message.length)
    println(c.c())
}

您是否可以通过在roupingBy和之间增加一个空格来将其减少到10个{
凯文·克鲁伊森

1
很好的发现,我换了其他11s并下降到10
jrtapsell

10个字符,但最长的子字符串不是roupingBy(9个字符)而是eachCount(带有尾随空格)。
暴民埃里克(Erik the Outgolfer)'18年

roupingBy 有一个尾随空格(在markdown中可见,但是渲染器似乎将其删除)
jrtapsell

设法将其减少到9,解决了修整问题
jrtapsell


0

05AB1E,22个字节| 得分:2

Œ  ʒ  D  Ù  Q  }  é  ¤

-1分+ 7字节感谢HeebyJeeby

在线尝试!


05AB1E,15个字节| 得分:3

Œ ʒ D Ù Q } é ¤

在线尝试!


05AB1E,8个字节| 得分:8

ŒʒDÙQ}é¤

在线尝试!


05AB1E实际上可以做一些相当便宜的事情……将空白添加到05AB1E中无济于事。

如果有反对的规则,我也可以使用´和喜欢其他7个字符。


1
@HeebyJeebyMan因为我是个白痴,对此有问题吗?
魔术章鱼缸

@HeebyJeebyMan开玩笑哈哈,谢谢你的主意。
魔术章鱼缸
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.