检查单词是否同构


63

两个词是同构,如果他们有字母重复相同的模式。例如,两个ESTATEDUELED都有模式abcdca

ESTATE
DUELED

abcdca

因为字母1和6相同,所以字母3和5相同,仅此而已。这也意味着单词由替换密码(此处与match)相关E <-> D, S <-> U, T <-> E, A <-> L

编写包含两个单词并检查它们是否同构的代码。最少的字节数获胜。

输入:两个非空的大写字母字符串A..Z。如果愿意,可以将它们作为两个字符串的集合或带分隔符的单个字符串。

输出:一致的Truthy值的对,是同构,并一致Falsey值,如果他们不。不同长度的字符串是有效输入,绝不为同形。

测试用例:

真正:

ESTATE DUELED
DUELED ESTATE
XXX YYY
CBAABC DEFFED
RAMBUNCTIOUSLY THERMODYNAMICS
DISCRIMINATIVE SIMPLIFICATION

假:

SEE SAW
ANTS PANTS
BANANA SERENE
BANANA SENSES
AB CC
XXY XYY
ABCBACCBA ABCBACCAB
ABAB CD

随意添加更多您认为有用的测试用例。

排行榜

这是一个堆栈片段,用于按语言生成常规排行榜和获胜者概述。

为确保您的答案显示出来,请使用以下Markdown模板以标题开头。

# Language Name, N bytes

N您提交的文件大小在哪里。如果您提高了分数,则可以通过打败旧分数保持标题。例如:

# Ruby, <s>104</s> <s>101</s> 96 bytes


两个输入的长度是否保证相同?
Optimizer

@Optimizer不,长度可以不同。
xnor 2015年

@Jakube不,理论上,您的代码应可使用任意长度的输入。如果由于内存溢出或堆栈深度等问题导致硬件上的大量输入失败,也可以。
xnor 2015年

好的,然后我将删除我的答案。
2015年

重要的测试案例:(ABAB CD适用于类似zip的方法)
Sp3000

Answers:


95

J,4个字节

-:&=

用法

   'THERMODYNAMICS' (-:&=) 'RAMBUNCTIOUSLY'  NB. parens are optional
1 

说明

  • = 带有1个参数的参数将创建一个相等表,该相等表将输入及其nub的元素进行比较。

    ='ESTATE' gives the binary matrix
    
    = | E S T A T E    
    --+------------
    E | 1 0 0 0 0 1
    S | 0 1 0 0 0 0
    T | 0 0 1 0 1 0
    A | 0 0 0 1 0 0
    
  • -:与2个参数一起检查它们的相等性(==通常一样)。这也适用于不同大小的矩阵(甚至不同类型)。

  • f&g将g分别应用于两个输入,然后将f应用于两个结果x f&g y == f(g(x), g(y))

  • 因此,在本例中,我们比较了两个相等表。

在这里在线尝试。


2
一种有趣而优雅的方法。没有这样的等效项&,您在K中可以做的最接近的事情可能是~/{x=/:x}',这会长很多。
JohnE

17
耶稣。这必须是代码高尔夫名人堂的竞争者。
Brian Gordon

哇,没想到分类=除了计数事件外还有其他用途。
英里

37

K,5个字节

这在K中具有令人愉悦的优雅解决方案!

~/=:'

“ group”运算符(monadic =)精确地创建了我们想要单词同构的签名;收集向量中每个元素的索引的向量,并按外观对各组进行排序:

  ="ABBAC"
(0 3
 1 2
 ,4)

  ="DCCDF"
(0 3
 1 2
 ,4)

以一对字符串为向量,我们只需要将group应用于每个元素(=:'),然后使用~深度匹配运算符“ match”()进行归约:

  ~/=:'("RAMBUNCTIOUSLY";"THERMODYNAMICS")
1
  ~/=:'("BANANA";"SERENE")
0

15

Python 2,41个字节

f=lambda a,b:map(a.find,a)==map(b.find,b)

4
这就是激发我创造挑战的解决方案!
xnor

12

CJam,9个字节

r_f#r_f#=

1如果单词是同构,0则打印,如果不是。

CJam解释器中在线尝试。

这个怎么运作

r    e# Read a whitespace separated token from STDIN.
_    e# Push a copy.
f#   e# Get the indexes of all characters from the first copy in the second.
r_f# e# Repeat for the second word.
=    e# Check for equality.

10

JavaScript,ES7、62 55 54 52 51字节

f=(x,y,g=z=>[for(i of z)z.search(i)]+0)=>g(x)==g(y)

逻辑很简单。我只是将两个输入都转换为它们相应的字符索引值,然后将该数组转换为字符串并进行比较。

f=(x, y,                  // Create a function named f which takes two arguments x and y
   g=                     // There is a third default argument to f which equals to
     z=>                  // and arrow function which takes argument z
     [                    // Return this array which is created using array comprehension
      for(i of z)         // For each character of z
      z.search(i)         // Use the index of that character in z in place of the character
     ]+0                  // And finally type cast that array to a string
                          // Here, the array elements are automatically joined by a ','
                          // and appended by a 0.
                          // Its funny how JS type casts Array + Number to a string
   )=>                    // Now the body of function f starts
      g(x)==g(y)          // It simply returns if index map of x equals index map of y

使用下面的代码段尝试上面的代码。

@ edc65节省了2个字节


7
+1,尝试过,效果很好。+0代替+""
edc65

1
@ edc65哇,类型转换WTF
Optimizer

1
我刚刚意识到字符串是“ A-Z”,因此您可以安全地使用search而不是indexOf并剪切另外1个字节。
edc65

数组理解最终还没有被削减吗?此代码在哪里工作?我认为仅在mozilla中
DanielIndie

8

Bash + coreutils,38岁

[ `tr $@<<<$1``tr $2 $1<<<$2` = $2$1 ]

请注意,我们在这里使用通常的壳真/虚假概念-零表示成功或TRUE,非零表示错误或FALSE:

$ for t in "ESTATE DUELED" "DUELED ESTATE" "XXX YYY" "CBAABC DEFFED" "RAMBUNCTIOUSLY THERMODYNAMICS" "DISCRIMINATIVE SIMPLIFICATION" "SEE SAW" "ANTS PANTS" "BANANA SERENE" "BANANA SENSES" "AB CC" "XXY XYY" "ABCBACCBA ABCBACCAB"; do
> ./isomorph.sh $t
> echo $t $?
> done
ESTATE DUELED 0
DUELED ESTATE 0
XXX YYY 0
CBAABC DEFFED 0
RAMBUNCTIOUSLY THERMODYNAMICS 0
DISCRIMINATIVE SIMPLIFICATION 0
SEE SAW 1
ANTS PANTS 1
BANANA SERENE 1
BANANA SENSES 1
AB CC 1
XXY XYY 1
ABCBACCBA ABCBACCAB 1
$ 

8

哈斯克尔,33 29

编辑:

这为时已晚,但我发现使用增补剂的情况有所改善,仅在2015年3月才添加。

s%k=g s==g k
g s=(==)<$>s<*>s

旧版本:

s%k=g s==g k
g s=[a==b|a<-s,b<-s]

检查功能是 (%)

这通过为每个字符串生成其“相等记录”来工作:对于每个两个索引ij,它记录它们是否具有相等的字符。记录是有序的,以便两个索引i,j的记录始终在同一位置*,因此检查记录的相等性将返回字符串是否具有相同的模式。

例如,“ ABC”的相等记录为[1,0,0,0,1,0,0,0,1](1表示是,0表示否)-在True此将任何索引与其自身进行比较。其他任何地方都是假的。(跳过这些检查可能更有效,但就高尔夫而言更难)

* 如果字符串长度相同。否则,由于记录长度不同,它返回false


6

Haskell,45 41字节

h l=map(`lookup`zip l[1..])l
x!y=h x==h y

返回TrueFalse,例如"ESTATE" ! "DUELED"-> True

使用在许多其他答案中看到的map-char-to-first-index方法。关联列表会派上用场,因为较早的条目会占优势。"aba"成为[(a,1),(b,2),(a,3)]那里lookup总是取a- > 1

编辑:@毛里斯发现要保存的4个字节。


您可以替换(flip lookup$zip l[1..])(`lookup`zip l[1..])
林恩

6

Brainfuck,169 168 162 144 140 131 130

与Alex Pankratov的bff(在SPOJ和ideone上使用的brainfuck解释器)和Thomas Cort的BFI(在Anarchy Golf上使用)兼容。

预期的输入是两个由制表符分隔的字符串,第二个字符串后没有换行符。输出适用1于同构和0非同构,这虽然不是最短的选择,但仍便于直观地检查结果。(更新:简短版本,在答案的底部带有\x01\x00作为输出以及\x00作为分隔符。)

示范的ideone。

,+
[
  -
  ---------
  >+<
  [
    >>-<
    [
      <
      [
        >+<
        <<<<-<+>>>>>-
      ]
      ++[->+]
      ->+[+<-]
      >[<<<<]
      <
    ]
    <[>+<-]
    +[->+]
    <->
    >>>
  ]
  >
  [
    [[-]<<<<<]
    >>>>
  ]
  <,+
]
>>>+>+
[
  [<->-]
  <[>>>>>]
  <<<<
]
-<[>]
+++++++[<+++++++>-]
<.

事实证明,这个问题对头脑操非常好。

索引的基本思想是从当前字符串前缀的末尾倒退。如果该字符以前没有出现过,我们可以使用字符串前缀的长度。例如:

STATES
123255

代码中的索引实际上稍有不同,但是使用相同的原理。

内存布局以5为块:

0 0 0 0 0 0 c 0 i p 0 c 0 i p 0 c 0 i p 0 0 0 0

c代表字符,i索引和p上一个(索引)。当处理第一个字符串时,所有p插槽均为零。左侧的单元格c用于保存我们要查找其索引的当前字符的副本。当前左侧的单元格i用于保存,-1以方便指针导航。

有许多条件需要仔细考虑。最后,我们通过比较各(i,p)对来检查同构,并且(i,p)当且仅当字符串是同构时,我们才能到达最左边的对左侧的零单元簇。以下是该代码的注释版本,以使其易于遵循:

,+
[                       while there is input
  -
  ---------
  >+<                   increment char (adjust later)
  [                     if not tab
    >>-<                set navigation flag
    [                   loop to find index
      <                 travel to copy
      [
        >+<             restore char
        <<<<-<+>>>>>-   compare chars and create copy
      ]
      ++[->+]           travel between navigation flags
      ->+[+<-]          increment index by 2 and go back
      >[<<<<]           proceed if not fallen off string
      <                 compare chars
    ]
    <[>+<-]             restore char (or no op)
    +[->+]              go back to navigation flag
    <->                 adjust char
    >>>                 alignment
  ]
  >
  [                     if tab
    [[-]<<<<<]          erase chars and go to beginning
    >>>>                alignment
  ]
  <,+
]
>>>+>+                  check string lengths and start loop
[
  [<->-]                compare indices
  <[>>>>>]              realign if not equal
  <<<<                  proceed
]
-<[>]                   cell to left is zero iff isomorphs
+++++++[<+++++++>-]
<.

更新:

这是一个打印\x01同构和\x00非同构的版本。由于方式[]工作原理,这可以说是对“真相”和“虚假”的更准确的解释。唯一的区别是在最后。

附加:现在\x00用作分隔符以节省10个字节。

+
[
  -
  >+<
  [
    >>-<
    [
      <
      [
        >+<
        <<<<-<+>>>>>-
      ]
      ++[->+]
      ->+[+<-]
      >[<<<<]
      <
    ]
    <[>+<-]
    +[->+]
    <->
    >>>
  ]
  >
  [
    [[-]<<<<<]
    >>>>
  ]
  <,+
]
>>>+>+
[
  [<->-]
  <[>>>>>]
  <<<<
]
-<[>]
<+.

5

JavaScript(ES6),62

使用h将每个单词映射到包含单词中每个字母位置的数组的aux函数,例如:PASS-> [1,2,3,3]。如果函数h应用的两个单词给出相同的结果,则返回true 。

f=(a,b,h=w=>0+[for(c of(n=k=[],w))k[c]=k[c]||++n])=>h(b)==h(a)

// TEST

;[
// True
 ['ESTATE','DUELED']
,['DUELED','ESTATE']
,['XXX','YYY']
,['CBAABC','DEFFED']
,['RAMBUNCTIOUSLY','THERMODYNAMICS']
,['DISCRIMINATIVE','SIMPLIFICATION']

// False:

,['SEE','SAW']
,['ANTS','PANTS']
,['BANANA','SERENE']
,['BANANA','SENSES']
,['XXY','XYY']
,['ABCBACCBA','ABCBACCAB']
]
.forEach(t=>(f(t[0],t[1])?OK:KO).innerHTML+=t+'\n')
Ok<br>
<pre id=OK></pre><br>
KO<br>
<pre id=KO></pre>


1
有时,简单的时间会更短;)
Optimizer

5

R,78

function(x,y)identical((g=function(z)match(a<-strsplit(z,"")[[1]],a))(x),g(y))

脱胶

word_to_num <- function(word) {
   chars <- strsplit(word,"")[[1]]
   match(chars, chars)
}
are_isomorph <- function(word1, word2) identical(word_to_num(word1), 
                                                 word_to_num(word2))

击败我!(+1)
Shadowtalker

我认为all( (g=...)(x)==g(y))identical... 短
Giuseppe

5

Ruby,83个字节

t=->x{y=0;z=?`;x.gsub!(y[0],z.succ!)while y=x.match(/[A-Z]/);x};f=->a,b{t[a]==t[b]}

这是一个函数f有两个参数,并返回truefalse

说明:

test = -> str {
    y = nil  # we're just initializing this; it doesn't matter to what
             # this is the variable we use to store the `match' result
    z = '`'  # backtick is the ASCII character before `a'
    while y = str.match(/[A-Z]/) do  # while there is an uppercase letter in str
        str.gsub!(y[0], z.succ!)  # replace all instances of the uppercase letter
                                  # with the next unused lowercase letter
    end
    str  # return the new string
}
# self-explanatory
f=->a,b{test[a]==test[b]}

1
这应该节省4个字节:t=->x{z=?`;x.chars.to_a.uniq.map{|c|x.gsub!(c,z.succ!)};x};f=->a,b{t[a]==t[b]},如果使用散列来获取替换,则可以将其降低到68:t=->x{h={};i=9;x.gsub!(/./){|c|h[c]||h[c]=i+=1}};f=->a,b{t[a]==t[b]}
blutorange

5

爪哇,107

(s,t)->java.util.Arrays.equals(s.chars().map(s::indexOf).toArray(),t.chars().map(t::indexOf).toArray())

MAP的每一个字符st它的位置,和平等检查。

展开:

class Isomorphs {
    public static void main(String[] args) {
        java.util.function.BiFunction<String, String, Boolean> f =
            (s, t) -> java.util.Arrays.equals(
                                              s.chars().map(s::indexOf).toArray(),
                                              t.chars().map(t::indexOf).toArray()
                                             )
           ;
        System.out.println(f.apply("XXY", "XYY"));
    }
}

如果字符串的长度不同,我认为这将无法正常工作。
JohnE

@JohnE是的,确实如此。
2015年

嗯,好吧,我认为“扩展”版本具有误导性。
JohnE

4

Python 3,85个字节

f=lambda a,b:''.join(map(lambda g:dict(zip(a,b))[g],a))==b
g=lambda a,b:f(a,b)&f(b,a)

这个输入/输出在哪里?
DJMcMayhem

@DJMcMayhem g是主要功能,f是助手。有变量的一个令人困惑的选择g里面f,但它是一个不相关的约束变量。该g=是可选的,因为每裁决允许匿名功能,从而节省了2个字符“。
xnor

4

Pyth,9个字节

qFmmxdkdQ

采取以下形式的输入:

"ESTATE", "DUELED"

如果不可接受,则以下代码为10个字节:

qFmmxdkd.z

并使用以下输入形式:

ESTATE
DUELED

在字符串表示形式中使用char的索引。


第一种输入格式很好。我对您如何减少检查相等性感兴趣,但不清楚如何F折叠。什么<binary>F
xnor 2015年

@xnor <binary>F<seq><binary>折叠了<seq>。等效于散布<binary>在的每对元素之间<seq>。因此,<binary>F在2元素序列上,只需将函数应用于序列即可,相当于.*Pyth或*Python。
isaacg 2015年

我以为QPyth隐含了尾随?
Cyoce '16

@Cyoce当时不是这样-差不多一年后,该功能于2016年4月添加。
isaacg '16

4

Matlab,50个字节

f=@(s,t)isequal(bsxfun(@eq,s,s'),bsxfun(@eq,t,t'))

该函数定义为匿名以节省空间。

例:

>> f=@(s,t)isequal(bsxfun(@eq,s,s'),bsxfun(@eq,t,t'));
>> f('ESTATE','DUELED')
ans =
     1
>> f('ANTS','PANTS')
ans =
     0

4

八度,26字节

@(s,t)isequal(s==s',t==t')

3
看起来很有趣。说明?
2015年

==是矩阵元素的等式,并且由于ss'的大小不同,倍频程的“广播”会自动尝试获取相同大小的矩阵以进行操作-在这种情况下,这意味着重复行s和列s'
rakslice

它与@LuisMendo的Matlab解决方案相同,但是扩展很明确。
rakslice

4

05AB1E,6个字节

εæδË}Ë

在线尝试!

将输入作为列表: ['ESTATE', 'DUELED']

说明:

    εæδË}Ë   Full program
    ε        Apply on each
     æ         Powerset
      δË       For each generated substring: 1 if all equal, 0 otherwise
        }    End for each
         Ë   1 if all equal, 0 otherwise

4

APL(Dyalog)5 4字节

-1感谢ngn的提示。

匿名默认前缀函数,它使用两个字符串的列表作为参数。

≡.⍳⍨

在线尝试!

这是一个内积,但不是通常的+×它使用

 相同性

. 和

 该ɩ ndex(各元件的第一次出现)

 整个两个元素的单词列表都用作两个参数

如果我们调用单词Aand B,那么我们可以按如下方式得出先前的解决方案:

≡.⍳⍨ A B
A B ≡.⍳ A B
(A⍳A) ≡ (B⍳B)
(⍳⍨A) ≡ (⍳⍨B)
≡/ ⍳⍨¨ A B

先前的解决方案

匿名默认前缀函数,它使用两个字符串的列表作为参数。

≡/⍳⍨¨

在线尝试!

 相同性

/ 跨越

 该ɩ ndex(各元件的第一次出现...)

 自拍照(…本身)

¨ 每个


你能看到内在的东西吗?:)
ngn

@ngn当然可以。真的是我
亚当

顶部链接应该链接到旧解决方案吗?
扎卡里

病人:太糟糕了,这不工作,虽然在更高级别的阵列
扎卡里


3

Mathematica,46个字节

Equal@@Values@*PositionIndex/@Characters@{##}&

3

Ruby,50个字节

红宝石代码短30个字节。在我看一下解决方案之前写过,检查两个字符串的每个字符,该字符首次出现的索引是否匹配;即。将字符串转换为其规范化形式,01121然后进行比较。

->x,y{g=->z{z.chars.map{|c|z=~/#{c}/}};g[x]==g[y]}

关于ideone的测试用例作为一项额外的奖励,这破坏了ideone的代码突出显示。


3

外壳,5个字节

¤=´×=

在线尝试!

说明

       -- implicit input A, B (strings aka character lists)       | "ab" "12"
¤=     -- apply the following function to A & B, then compare:    | [1,0,0,1] == [1,0,0,1] -> 1
  ´×   --   Cartesian product with itself under                   | ["aa","ba","ab","bb"] ["11","21","12","22"]
    =  --   equality                                              | [ 1  , 0  , 0  , 1  ] [ 1  , 0  , 0  , 1  ]

3

PCRE,84个字节

^((.)(?=.+ (\3.|)(.))(?=((?=(\2|)?+.* \3\4(\7?(?(?=.*+\6)(?!\4).|\4))).)+ ))+. \3..$ 

主题应该是两个空格分隔的单词,如在OP中一样。这是一个粗略的解释:

对于第一个单词中的每个字母X:

向前看第二个单词并建立向后引用,以回忆我们以及第二个单词中对应于X的字母Y的距离。

对于第一个单词中当前位置之后的每个字母Z:

建立与上述类似的反向参考。

向前看第二个单词中的相应字母,然后检查Z = X然后匹配Y,否则匹配不是Y的字母。

一旦我们匹配到第一个单词的倒数第二个字母,该迭代就可以结束。在这一点上,由于不需要进一步的验证,因此剩下的全部工作就是测试这些单词的长度是否相等(包含第二个单词的累积子字符串的后向引用始终落后1个字母)。


2

Ruby,31个字节

->a{!!a.uniq!{|s|s.tr s,'a-z'}}

一个Proc,它接收字符串数组,并检查是否彼此同构。tr s,'a-z'带有这些参数的字符串s通过将每个字母替换为字母中的第n个字母来规范化字符串,其中n n是该字母出现在字符串中的最大索引。例如,estatefbedef,象dueled


1

眼镜蛇,72字节

do(a='',b='')=(for i in a get a.indexOf(i))==for i in b get b.indexOf(i)

您确定这会将AB CC测试用例标记为False吗?
xnor 2015年

@xnor现在已修复
很有

1

JavaScript(ES5),142 98

很大,但是我还没有看到ES5版本。

for(l=j=2;j--;){c=prompt();for(i=c.length;i--;)c=c.replace(RegExp(c[i],"g"),i);b=l==c;l=c}alert(b)

只需用它的反向索引值替换第一个字母的每次出现。对每个字符重复此操作。

它对两个输入都执行相同的操作,并比较生成的模式。

比较是很丑陋的,但是我不希望使用数组来存储和比较它。


1
你能不动;l=c,以for(l=j=2;j--;节省一个字节?
乔纳森·弗雷希

1

Perl,38个字节

($_,$a)=@ARGV;eval"y/$_/$a/";say$_~~$a

运行为 perl -E '($_,$a)=@ARGV;eval"y/$_/$a/";say$_~~$a' RAMBUNCTIOUSLY THERMODYNAMICS

如果为true,则输出1;如果为false,则不输出。



1

C ++,213个 196 162字节

-51字节,感谢Zacharý

#include<map>
#define F(X,x)for(auto&e:X){if(x.end()==x.find(e))x[e]=65+x.size();e=x[e];}
auto i=[](auto a,auto b){std::map<int,int>c,d;F(a,c)F(b,d)return a==b;};

要调用lambda,您需要传递两个参数 std::string数据类型的

测试代码:

std::initializer_list<std::pair<std::string, std::string>> test{
    {"ESTATE","DUELED"},
    {"DUELED","ESTATE"},
    {"XXX","YYY"},
    {"CBAABC","DEFFED"},
    {"RAMBUNCTIOUSLY","THERMODYNAMICS"},
    {"DISCRIMINATIVE","SIMPLIFICATION"},
    {"SEE","SAW"},
    {"ANTS","PANTS"},
    {"BANANA","SERENE"},
    {"BANAnA","SENSES"},
    {"AB","CC"},
    {"XXY","XYY"},
    {"ABCBACCBA","ABCBACCAB"},
    {"ABAB","AC"}
};

for (const auto& a : test) {
    std::cout << "Test with " << a.first << " and " << a.second <<
        " outputs : " << (i(a.first, a.second)?"TRUE":"FALSE") << '\n';
}

用于测试的代码,包括iostreamstring头文件是必需的


1
看起来您没有使用字符串标题中的任何内容,因此可以将其删除并让用户自己包括吗?
扎卡里

请问这个工作161个字节?
扎卡里

@Zacharý如果您添加的eas参数find,是的,它可以正常工作
HatsuPointerKun 17-10-5

当你被击败Brainfuck虽然> _ <那一刻
扎卡里

1

JavaScript(ES6),52 51 50字节

此版本不使用数组推导,而是使用currying语法接收输入。

a=>b=>(f=x=>0+[...x].map(c=>x.search(c)))(a)==f(b)

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.