最短的唯一子串


14

给定(在STDIN上,作为命令行参数或作为函数参数)两个截然不同的非空字符串,查找并返回第一个字符串的最短子字符串,而不是第二个字符串的子字符串。如果不存在这样的子字符串,则可以返回空字符串,返回不是原始字符串的子字符串的任何字符串,或者引发异常。如果要从函数返回,则在这种情况下也可能返回null(或未定义,None等)。如果将多个这样的子字符串捆绑在一起,则您可以返回其中的任何一个。

字符串可以包含任何可打印的ASCII字符。

在STDIN上给出的输入将在每一行上给出一个字符串。根据您的要求,可以在输入末尾添加一个空行。

这是代码高尔夫球,因此最短的有效程序将获胜。

一些测试案例

输入:

STRING ONE
STRING TWO

输出:

E

输入:

A&&C
A&$C

有效输出:

&&
&C

输入:

(两个随机生成的80个字母的字符串)

QIJYXPYWIWESWBRFWUHEERVQFJROYIXNKPKVDDFFZBUNBRZVUEYKLURBJCZJYMINCZNQEYKRADRYSWMH
HAXUDFLYFSLABUCXUWNHPSGQUXMQUIQYRWVIXGNKJGYUTWMLLPRIZDRLFXWKXOBOOEFESKNCUIFHNLFE

所有有效输出:

AD
BJ
BR
CZ
DD
EE
ER
EY
EY
FF
FJ
FW
FZ
HE
IJ
IN
IW
JC
JR
JY
KL
KP
KR
KV
LU
MH
MI
NB
NQ
OY
PK
PY
QE
QF
QI
RA
RB
RF
RO
RV
RY
RZ
SW
UE
UH
UN
UR
VD
VQ
VU
WB
WE
WI
WU
XN
XP
YI
YK
YK
YM
YS
YW
YX
ZB
ZJ
ZN
ZV

1
最短还是最长?
Leaky Nun

@FryAmTheEggman然后我还是应该发布我的解决方案吗?
Leaky Nun

“每行一个字符串”是否带引号?
Leaky Nun

1
我们可以接受一个字符串数组吗?
丹尼斯

“ B”是“ aBc”的子字符串吗?
downrep_nation '16

Answers:


4

Brachylog,23个字节

:1foh.,{,.[A:B]hs?'~sB}

适用于旧的Java编译器。期望列表中的两个字符串作为输入,将输出与子字符串统一。如果未找到子字符串,则返回false。

不幸的是,我还没有编码新的Prolog编译器中内置的子集。

说明

:1f               Find all bindings which satisfy predicate 1 with that binding as input and
                  with the Input of the main predicate as output.
   oh.,           Order that list of bindings, and unify the output with the first one.

{
 ,.[A:B]          Unify the output with the list [A,B]
        hs?       Unify the input with a subset of A
           '~sB   Check that no subset of B can be unified with the input
               }

4

Python,119 115 91

lambda a,b:[a[m:m+n]for n in range(1,len(a)+1)for m in range(len(a))if a[m:m+n]not in b][0]

测试用例:

| Input 1  | Input 2     | Output        |
|----------+-------------+---------------|
| 'abcd'   | 'abc'       |  'd'          |
| 'abcd'   | 'dabc'      |  'cd'         |
| 'abcd'   | 'dcbabbccd' |  'abc'        |
| 'abcdf'  | 'abcdebcdf' |  'abcdf'      |
| 'abc'    | 'abc'       |  (IndexError) |

努力使其更短,但这是我的大脑本能。还不是真正的高尔夫球手。

感谢@ user81655和@NonlinearFruit的额外字节。

编辑

ang 试过这段代码:

def z(a,b):
 for s in [a[m:m+n]for n in range(1,len(a)+1)for m in range(len(a)-n+1)]:
  if s not in b:return s
 return''

以为它短了几个字节。原来比我编辑前长了1个字节。


我对Python的了解不多,但是也许您可以(r=range)(1,len(a)+1)然后使用r吗?
科纳·奥布莱恩

@CᴏɴᴏʀO'Bʀɪᴇɴ不能那样做。如果我在上面的行中分配ranger它,它实际上会添加一个字节。好主意。可能有更短的方法来遍历子字符串。
泰勒·洛佩兹

range(1,len(a))并且range(len(a)-1)应该工作吗?我也认为对两个空格缩进使用制表符会节省一个字节。
user81655 '16

不,使用range(1,len(a)),第4次测试强制转换失败,因为它不会尝试完整的字符串;它只会到达字符串的长度-1。而且range(len(a)-1),第一个测试用例无法返回,'cd'而不仅仅是返回'd'。不过那里可能有些东西。
泰勒·洛佩兹

抱歉,我对Python不熟悉,我认为范围是包含范围的。在这种情况下,尝试range(1,len(a)+1)range(len(a))
user81655 '16

3

Python,87 86字节

lambda s,t,e=enumerate:[s[i:i-~j]for j,_ in e(s)for i,_ in e(s)if(s[i:i-~j]in t)<1][0]

如果存在,它将返回所有最短的唯一子字符串中最左边的一个。

如果没有唯一的子字符串,则会引发IndexError

Ideone上进行测试


在那里。我在等待有人杀死我的非lambda实现。哈哈
Taylor Lopez

我认为您可以通过提供可选的第二个参数enumerate开始j以缩短此时间i+1
user2357112支持Monica's

@ user2357112 不幸的是,这引发了NameError。该代码j首先定义,然后定义i
丹尼斯

@丹尼斯:是的,但不是必须的。您可以切换循环顺序。
user2357112支持Monica's

1
@ user2357112如果我切换循环顺序,则它找到的第一个唯一子字符串可能不是最短的。只需将订单退回交换'ab'为输入'abc','aaa'
丹尼斯

2

Python,82个字节

g=lambda u:{u}|g(u[1:])|g(u[:-1])if u else{''}
f=lambda s,t:min(g(s)-g(t),key=len)

用法:f('A&&C', 'A&$C')->返回'&&'

如果没有合适的子字符串,则引发ValueError。

说明:

g=lambda u:{u}|g(u[1:])|g(u[:-1])if u else{''}递归地创建一组子串,其中子串的集合中的子串u f=lambda s,t:min(g(s)-g(t),key=len)最短


2

JavaScript(ES6),79个字节

f=
(a,b)=>[...a].some((_,i,c)=>c.some((_,j)=>b.indexOf(s=a.substr(j,i+1))<0))?s:''
<div oninput=o.textContent=f(a.value,b.value)><input id="a"/><input id="b"/><pre id=o>

如果false可以接受返回,请使用&&s代替来保存2个字节?s:''



1

JavaScript(Firefox),80字节

solution=

a=>b=>[for(_ of(i=0,a))for(_ of(j=!++i,a))if(b.includes(s=a.substr(j++,i)))s][0]

document.write("<pre>"+
[ [ "test", "best" ], [ "wes", "west" ], [ "red", "dress" ] ]
.map(c=>c+": "+solution(c[0])(c[1])).join`\n`)

测试仅在Firefox中有效。undefined如果没有子字符串,则返回。


字符串可以包含可打印的ASCII字符,例如\或其他RegExp元字符,但是如果您将自己限制为Firefox,为什么不使用它b.includes呢?
尼尔

@Neil问题没有说字符串之前可以是任何字符,但感谢您让我知道!更新为使用includes
user81655 '16

1
测试SyntaxError: unexpected token 'for'
摘要

@NoOneIsHere如果您不使用Firefox,这将是您得到的错误...
user81655 '16

1

视网膜,37字节

M!&`\G(.+?)(?!.*¶.*\1)
O$#`.+
$.&
G1`

如果在中找不到有效的子字符串,则输出为空A

在线尝试!(稍作修改即可一次运行多个测试用例。输入格式实际上是换行分隔的,但是测试套件最容易以每行一个测试用例编写。测试框架在实际代码开始之前将空间转换为换行。)

说明

M!&`\G(.+?)(?!.*¶.*\1)

对于in中的每个可能的起始位置A,匹配不出现在中的最短子串B。该&是重叠的匹配,这样,我们实际上是想尽各种起始位置,即使一场比赛是超过一个字符长。将\G确保我们不要跳过任何位置-尤其是这样,我们必须停止在换行,这样,我们没有从获得额外的比赛B本身。这不会弄乱事情的原因实际上是很微妙的:因为如果A在我们找不到任何有效子字符串的起始位置,那也是一个失败,将导致\G停止检查任何其他位置。但是,如果(从当前起始位置开始)所有子字符串都出现在B,所有从当前位置开始的子字符串也将如此,因此丢弃这些子字符串不是问题(实际上可以提高性能)。

根据M!配置,所有这些匹配项都将从舞台中返回,并与换行符一起使用。

O$#`.+
$.&

这将按长度对先前结果的行进行排序。这是通过将行与匹配来完成的.+。然后$激活一种“排序依据”形式,以便将匹配替换$.&为确定排序顺序。将$.&自身替换匹配它的长度。最后,该#选项告诉Retina对数字进行排序(否则,它将把生成的数字视为字符串,然后按字典顺序对其进行排序)。

G1`

最后,我们使用带有空正则表达式(始终匹配)且限制为的grep阶段,仅保留第一行1


1

Perl, 87 85

sub{(grep{$_[1]!~/\Q$_/}map{$}=$_;map{substr($_[0],$_,$})}@}}(@}=0..length$_[0]))[0]}

这是一个匿名函数,它返回中$_[0]没有出现的最短子串的第一个(按位置)$_[1],或者undef不存在这样的子串。

使用从@iAmMortos的答案中提取的字符串进行测试的程序,并使用Perl 5.22.1进行了测试:

#!/usr/bin/perl -l
use strict;
use warnings;

my $f = <see above>;
print $f->('abcd', 'abc');
print $f->('abcd', 'dabc');
print $f->('abcd', 'dcbabbccd');
print $f->('abcdf', 'abcdebcdf');
print $f->('abc', 'abc');

1

Haskell,72个字节

import Data.Lists
a#b=argmin length[x|x<-powerslice a,not$isInfixOf x b]

用法示例:"abcd" # "dabc"-> "cd"

一个简单的实现:构建的所有子字符串 a并保留未出现在中的bargmin返回列表的元素,该列表将给定第二个参数的函数减到最小,这里是:length


我不知道argmin!似乎非常有用。
Zgarb '16

0

腐霉菌- 9 6个字节

h-Fm.:

在这里在线尝试


划掉9仍然是9

我想知道这是如何工作的。
mroman

@mroman the。:只有一个args是所有substrs。因此,我将其映射到两个字符串上,然后折叠差异化的差异,因此我拥有第一个的所有子字符串,第二个具有arnt,然后选择第一个,最小的cuz。:被排序。
Maltysen

0

C#,152个字节

string f(string a,string b){int x=a.Length;for(int i=1;i<=x;i++)for(int j=0;j<=x-i;j++){var y=a.Substring(j,i);if(!b.Contains(y))return y;}return null;}

0

Ruby,70个字节

从第一个字符串中收集一定长度的所有子字符串,如果第二个字符串中没有某个子字符串,则将其返回。

->a,b{r=p;(1..l=a.size).map{|i|(0...l).map{|j|b[s=a[j,i]]?0:r||=s}};r}

0

滑稽-26字节

现在,我能想到的最短的方法是:

lnp^sujbcjz[{^p~[n!}f[-][~

0

Japt,14个字节

Êõ!ãU c k!èV g

在线尝试!

undefined如果没有有效的substring,则返回。这与返回字符串“ undefined”不同,尽管仅由于-Q标志才可见差异。

说明:

Ê                 :Length of the first input
 õ                :For each number in the range [1...length]:
  !ãU             : Get the substrings of the first input with that length
      c           :Flatten to a single array with shorter substrings first
        k         :Remove ones which return non-zero to:
         !èV      : Number of times that substring appears in second input
             g    :Return the shortest remaining substring

0

Japt -h,11个字节

à f@øX «VøX

尝试一下

                :Implicit input of strings U & V
à               :All combinations of U
  f@            :Filter each as X
    øX          :  Does U contain X?
       «        :  Logical AND with the negation of
        VøX     :  Does V contain X?
                :Implicit output of last element
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.