紧密联系的挑战


40

无聊时我有时会做的一项活动是成对地写几个字符。然后,我画线(从不超过顶部)连接这些字符。例如,我可能会写abcbac,然后将线画为:

第一链接

或者我可能会写abbcac

第二连结

绘制完这些线条后,我会尝试在块周围绘制闭合循环,以使我的循环不会与我刚刚绘制的任何线条相交。例如,在第一个循环中,我们可以绘制的唯一循环是围绕整个对象,但是在第二个循环中,我们可以绘制仅围绕b的循环(或其他所有东西)

绘制循环

如果我们花一点时间来研究它,我们会发现只能绘制一些字符串,以便闭环包含所有字母或不包含所有字母(如第一个示例)。我们将这些字符串称为链接良好的字符串。

请注意,某些字符串可以多种方式绘制。例如,bbbb可以通过以下两种方式绘制(不包括第三种):

方式1 要么 方式2

如果可以绘制这些方式中的一种,从而可以使闭环包含一些字符而不与任何行相交,则该字符串未很好地链接。(所以bbbb没有很好地链接)

任务

您的任务是编写一个程序来识别链接良好的字符串。您的输入将由一个字符串组成,其中每个字符均出现偶数次,并且您的输出应为两个不同的一致值之一,如果字符串连接正确,则为一个,否则为另一个。

另外你的程序必须是一个很好地链接字符串意义

  • 每个字符在程序中出现偶数次。

  • 通过时应输出真实值。

您的程序应该能够为由可打印ASCII或您自己的程序中的字符组成的任何字符串产生正确的输出。每个字符出现偶数次。

答案将以其长度(以字节为单位)进行评分,而字节越少越好。

暗示

如果存在连续的非空严格子字符串,则字符串连接不正确,从而每个字符在该子字符串中出现偶数次。

测试用例

abcbac -> True
abbcac -> False
bbbb -> False
abacbc -> True
abcbabcb -> True
abcbca -> False

1
测试案例:abcbca -> False
与Orjan约翰森

我认为您的提示包含多余的内容there
乔纳森·弗雷希

2
需要明确的是:字符串是否每个字符的总数为偶数与它是否是链接良好的字符串无关。该要求仅适用于程序的源代码。当然,这仅是语义问题,因为对于任何字符的奇数总数的输入字符串,程序被允许具有未定义的行为(并且至少一个提交的程序利用了这一点)。
Deadcode

输入中可以包含哪些字符?
xnor

@xnor我将其添加到了挑战中。希望这可以解决。
小麦巫师

Answers:


19

正则表达式(ECMAScript的2018或.NET),140 126 118 100 98 82个字节

^(?!(^.*)(.+)(.*$)(?<!^\2|^\1(?=(|(<?(|(?!\8).)*(\8|\3$){1}){2})*$).*(.)+\3$)!?=*)

这比98字节的版本要慢得多,因为^\1前瞻的左侧是,因此在之后进行评估。请参阅以下有关重新获得速度的简单switcheroo。但是由于这个原因,下面的两个TIO只能完成比以前更小的测试用例集,.NET太慢了,无法检查自己的正则表达式。

在线尝试!(ECMAScript 2018)
在线尝试!(。净)

要删除18个字节(118→100),我无耻地从Neil的正则表达式中窃取了一个非常不错的优化,它避免了在负向后的内部留一个先行(产生80字节的不受限制的正则表达式)。谢谢,尼尔!

由于jaytea的想法导致了69字节无限制的正则表达式,它又掉了16个字节(98→82),这变得过时了!它慢得多,但这就是高尔夫!

请注意,(|(使正则表达式良好链接的无操作的结果是使它在.NET下的评估非常缓慢。它们在ECMAScript中没有此效果,因为零宽度的可选匹配被视为非匹配

ECMAScript禁止在断言上使用量词,因此这使要求打高尔夫变得更加困难。但是,在这一点上,它是如此出色,以至于我认为取消这一特定限制不会为高尔夫运动带来更多可能性。

没有通过限制的额外字符(101 69字节):

^(?!(.*)(.+)(.*$)(?<!^\2|^\1(?=((((?!\8).)*(\8|\3$)){2})*$).*(.)+\3))

速度很慢,但是这个简单的编辑(仅增加2个字节)重新获得了所有丢失的速度,甚至更多:

^(?!(.*)(.+)(.*$)(?<!^\2|(?=\1((((?!\8).)*(\8|\3$)){2})*$)^\1.*(.)+\3))

^
(?!
    (.*)               # cycle through all starting points of substrings;
                       # \1 = part to exclude from the start
    (.+)               # cycle through all ending points of non-empty substrings;
                       # \2 = the substring
    (.*$)              # \3 = part to exclude from the end
    (?<!               # Assert that every character in the substring appears a total
                       # even number of times.
        ^\2            # Assert that our substring is not the whole string. We don't
                       # need a $ anchor because we were already at the end before
                       # entering this lookbehind.
    |                  # Note that the following steps are evaluated right to left,
                       # so please read them from bottom to top.
        ^\1            # Do not look further left than the start of our substring.
        (?=
            # Assert that the number of times the character \8 appears in our
            # substring is odd.
            (
                (
                    ((?!\8).)*
                    (\8|\3$) # This is the best part. Until the very last iteration
                             # of the loop outside the {2} loop, this alternation
                             # can only match \8, and once it reaches the end of the
                             # substring, it can match \3$ only once. This guarantees
                             # that it will match \8 an odd number of times, in matched
                             # pairs until finding one more at the end of the substring,
                             # which is paired with the \3$ instead of another \8.
                ){2}
            )*$
        )
        .*(.)+         # \8 = cycle through all characters in this substring
        # Assert (within this context) that at least one character appears an odd
        # number of times within our substring. (Outside this negative lookbehind,
        # that is equivalent to asserting that no character appears an odd number
        # of times in our substring.)
        \3             # Skip to our substring (do not look further right than its end)
    )
)

我使用分子先行(103 69字节)编写了该代码,然后将其转换为可变长度先行代码:

^(?!.*(?*(.+)(.*$))(?!^\1$|(?*(.)+.*\2$)((((?!\3).)*(\3|\2$)){2})*$))

^
(?!
    .*(?*(.+)(.*$))       # cycle through all non-empty substrings;
                          # \1 = the current substring;
                          # \2 = the part to exclude from the end
    (?!                   # Assert that no character in the substring appears a
                          # total even number of times.
        ^\1$              # Assert that our substring is not the whole string
                          # (i.e. it's a strict substring)
    |
        (?*(.)+.*\2$)    # \3 = Cycle through all characters that appear in this
                          # substring.
        # Assert (within this context) that this character appears an odd number
        # of times within our substring.
        (
            (
                ((?!\3).)*
                (\3|\2$)
            ){2}
        )*$
    )
)

为了帮助我的正则表达式本身建立良好的链接,我一直在使用上述正则表达式的变体:

(?*(.+)(.*$))(?!^\1$|(?*(.)+.*\2$)((((?!\3).)*(\3|\2$)){2})*$)\1

与一起使用时regex -xml,rs -o,它将标识输入的严格子字符串,其中包含偶数个每个字符(如果存在)。当然,我可以编写一个非正则表达式程序来为我执行此操作,但是这样做的乐趣何在?


8
wtf它仍然在打高尔夫球
仅支持ASCII

@仅ASCII并且仍在打高尔夫球……
Quintec

11

果冻,20个字节

ĠẈḂẸẆṖÇ€Ạ
ĠẈḂẸ
ẆṖÇ€Ạ

在线尝试!

第一行被忽略。只有满足每个字符出现偶数次的条件。

下一行首先Ġ按其值启动索引。然后,如果我们使用结果列表()中每个子列表的长度,我们将获得每个字符出现的次数。为了检查这些值是否为非偶数,我们获取每个计数的最后一个值,并询问是否存在真值(非零)。

因此,此帮助链接返回是否无法圈出子字符串。

在主链接中,我们取出输入()的所有子字符串,然后关闭最后一个(以免检查整个字符串是否可以圈起来),然后对每个子字符串运行辅助链接(Ç。然后的结果是是否无法圈出ll个子字符串。


所以,是的,也是我的解决方案,但是,不幸的是,这很无聊... :(
Egg the Outgolfer

8

J,34个字节

2:@':.,|~*'>1(#.,)*/@(1>2|#/.~)\.\

在线尝试!

-8字节归功于FrownyFrog

原版的

J,42个字节

(*#'.,012&|@~#')=1#.[:,([:*/0=2&|@#/.~)\.\

在线尝试!

说明

(*#'.,012&|@~#') = 1 #. [: , ([: */ 0 = 2&|@#/.~)\.\

(*#'.,012&|@~#')                                       NB. this evaluates to 1
                                                       NB. while supplying extra
                                                       NB. chars we need.  hence...
                 =                                     NB. does 1 equal...
                   1 #.                                NB. the sum of...
                        [: ,                           NB. the flatten of...
                             (                  )\.\   NB. the verb in parens applied
                                                       NB. to every suffix of every
                                                       NB. prefix, ie, all contiguous 
                                                       NB. substrings
                             ([: */ 0 = 2&|@#/.~)      NB. def of verb in paren:
                                             /.~       NB. when we group by each
                                                       NB. distinct char...
                              [: */                    NB. is it the case that
                                                       NB. every group...
                                           @#          NB. has a length...
                                    0 = 2&|            NB. divisible by 2...

1
@Deadcode由于处理该操作相当于对整个字符串和其他所有子字符串进行相反的测试,因此可以肯定地认为,大多数解决方案都将其排除在外。使用进行测试abc,只有Perl条目不会在其上“失败”。(尽管它还有其他问题。)
ØrjanJohansen

1
@ØrjanJohansen您误会了。我说过,任何字符的总数为奇数的字符串(只会使程序的源代码不合格,而不能使链接正确的字符串)可以被很好地链接,并且该程序对于某些链接良好的字符串返回false。该问题明确允许这种未定义的行为,因此该程序有效。乔纳(Jonah),我认为您的程序做到这一点真的很有趣,而且我很佩服您找到了一种可以这样工作的方法。我想解释一下。这种编程对我来说完全是陌生的,所以我不理解注释和代码。
Deadcode

1:@':.,02|~*'=1(#.,)*/@(0=2|#/.~)\.\
FrownyFrog

1
2:@':.,|~*'>1(#.,)*/@(1>2|#/.~)\.\似乎也有效
FrownyFrog

6

Python 3.8(预发布),66字节

lambda l,b={id}:len({str(b:=b^{c})for(c)in l})<len(l)#,<^fmnost{}#

在线尝试!

赋值表达式的时代已经来临。使用Python 3.8中包含的PEP 572,打高尔夫球将不再是一样的。您可以在此处安装早期的开发人员预览版3.8.0a1 。

赋值表达式使您可以:=在评估该值时用于内联变量。例如,(a:=2, a+1)给出(2, 3)。当然,这可以用于存储变量以供重用,但是在这里,我们更进一步,将其用作理解的累加器。

例如,此代码计算累计和 [1, 3, 6]

t=0
l=[1,2,3]
print([t:=t+x for x in l])

请注意,每次通过列表理解时,累积总和如何t增加,x并将新值存储在该理解产生的列表中。

同样,b:=b^{c}更新字符集b以切换是否包含字符c,并求值为的新值b。所以,代码[b:=b^{c}for c in l]遍历字符cl并累积在每个非空前缀观察的奇数倍的一组字符。

通过将其设置为集合来检查此列表是否存在重复项,并查看其长度是否小于的长度s,这意味着某些重复项已折叠。如果是这样,则重复表示s在这些时间之间看到的部分中,每个字符都遇到偶数个数字,从而使字符串无法很好地链接。Python不允许将集合集设为不可散列,因此将内部集合转换为字符串。

该集合b将初始化为可选参数,并在函数范围内成功进行修改。我担心这会使该功能不可重用,但似乎在两次运行之间会重置。

对于源限制,末尾的注释中会填充未配对的字符。写作for(c)in l而不是for c in l免费取消多余的部分。我们将id初始集合放入b,这是无害的,因为它可以作为任何集合开始,但是空集合不能写为{}因为Python将生成一个空字典。由于字母id是需要配对的字母,因此我们可以将函数放在id此处。

请注意,代码输出的是取反的布尔值,因此它将正确地给出False自身。



5

Python 2,74个字节

bmn0=f=lambda s,P={0},d=[]:s<" "if(P in d)else+f(s[f<s:],P^{s[0^0]},[P]+d)

在线尝试!

遍历字符串,跟踪P迄今出现过奇数次的字符集。该列表d存储的所有过去的值P,如果看到当前P已在d,这意味着,自那时以来,看到的字符,每个字符出现的次数为偶数。如果是这样,请检查是否已遍历整个输入:如果有,请接受,因为整个字符串均按预期配对,否则拒绝。

现在关于源限制。需要配对的字符被塞入各种无害的位置,以下划线所示:

bmn0=f=lambda s,P={0},d=[]:s<" "if(P in d)else+f(s[f<s:],P^{s[0^0]},[P]+d)
_____              _              _      _    _    ___        ___    

配对一个时,对的f<s求值为,0同时f也利用了函数名,f以便对其进行定义(在调用函数时。)0^0吸收^符号。

0P={0}不幸的是:Python中{}的计算结果为空字典,而不是我们想要一个空集,在这里,我们可以把任何非字符元素,这将是无害的。我看不到任何多余的东西,已经放入0并复制了bmn0,花费2个字节。请注意,在定义函数时会评估初始参数,因此我们定义的变量不能放在此处。


4

Perl 6,76个字节

*.comb[^*X+(^*).map(^*)].grep({$_&[&]($_)}).none.Bag{*}.none%2#*^+XBob2rec%#

在线尝试!

传回None结的None结的Any lambda,可以将其布尔化为true / falsey值。我建议您不要删除?会影响返回结果的,否则输出将变得很大

该解决方案是一个小比需要更复杂的,由于被取消关联几个涉及的功能,例如..all>>%%等等没有限制源,这可以是43个字节:

*.comb[^*X.. ^*].grep(?*).one.Bag{*}.all%%2

在线尝试!

说明:

*.comb                     # Split the string to a list of characters
      [^*X+(^*).map(^*)]   # Get all substrings, alongside some garbage
                        .grep({$_&[&]($_)})        # Filter out the garbage (empty lists, lists with Nil values)
                                           .none                 # Are none of
                                                .Bag{*}          # The count of characters in each substring
                                                       .none%2   # All not divisible by 2

                                               #*^+XBob2rec%#    And garbage to even out character counts

3

Perl 5中-p94, 86, 78个字节

m-.+(?{$Q|=@q&grp,$\|=$&eq$_^!grep+/^/&(@m=$g=~/\Q$_/g),($g=$&)=~/./g})(?!)-}{

如果链接良好,则输出0;否则,输出1。

78字节

86字节

94字节

这个怎么运作

  • -p}{结束绝招输出$\
  • m-.+(?{.. })(?!)-,以在所有非空子字符串上执行代码(首先.+匹配整个字符串,然后由于强制失败而在(?{.. })backtracks 之间执行代码之后(?!)
  • $Q|=@q&grp, 由于源限制而产生垃圾
  • $\|=按位整数或赋值,如果几乎为1,则为$\1(true),默认情况下为空(false)
  • $&eq$_sbustring是整个字符串的情况按^“没有出现奇数字符” 按位异或
  • ($g=$&)=~/./g将匹配的子字符串复制到$g(因为在下一个正则表达式匹配后将被覆盖)并返回子字符串的字符数组。
  • /^/ 值为1的垃圾
  • grep&(@m=$g=~/\Q$_/g),对于子字符串中的每个字符,为1则得到$g与其自身匹配的字符数组,标量数组将求值其大小并grep过滤出现奇数的字符1&x等于x%2==1

我认为这不能满足源代码的限制:例如,我计算了一个奇数个开放括号,例如
msh210

@ msh210不是重点吗?如果有偶数,则表示链接不紧密
Quintec

用于被很好地链接@Quintec其中一个要求是,有每个字符的一个偶数。
与Orjan约翰森

我的第一个答案有这个要求,但是尝试打高尔夫球之后就迷失了。更新,但可以打高尔夫球。
Nahuel Fouilleul

1
此处所有源均满足源限制,如果每个字符的链接正确且偶数个,代码也将返回0
Nahuel Fouilleul

3

视网膜150 96字节

^(?!(.*)(.+)(.*)$(?<!^\2|^\1(?:(^?(?:(?!\6).)*\6){2})*(|(?!\6).)*(?!.+\6.*\3$)(.){1,}\3)(?!,<)?)

在线尝试!链接包括测试用例,包括其本身。编辑:在@Deadcode的帮助下,对原始正则表达式进行了合理的调整,然后稍微减少了多余的填充以保持源布局。说明:

^(?!(.*)(.+)(.*)$

断言不\3存在与以下约束匹配的子字符串。

(?<!^\2|

断言子字符串不是整个原始字符串。

^\1(?:(^?(?:(?!\6).)*\6){2})*(|(?!\6).)*(?!.+\6.*\3$)(.){1,}\3)(?!,<)?)

断言没有\6这样的字符:

  • 它不会出现在字符本身(排他)和子字符串末尾之间
  • 在子字符串的开始和它本身之间出现偶数次(不包括)

为了传递源布局约束,我(((((?:(^?(?:(和替换(((|(。我仍然有一个源约束))左和人物!()1<{}遗留下来的,所以我换了一个+进入{1,}并插入无用(?!,<)?消耗休息。


2
这似乎无法满足有限的货源要求。
与Orjan约翰森

@ØrjanJohansen最后,我想出了一个有效的解决方案。尽管那里有很多垃圾,所以可能会有一些更短的可用...
尼尔·

3

C#(Visual C#中交互式编译器)208个 206 200 198字节

x=>!x.GroupBy(c=>c).Any(g=>g.Count()%2>0)&!Enumerable.Repeat(x.Count,x.Count*x.Count).Where(
(l,i)=>i%l>0&!x.Skip(i/l).Take(i%l).GroupBy(c=>c).Any(g=>g.Count()%2>0)
).Any()/*>!oyAnC0EmeablR*WhiS/T*/

在线尝试!

-2个字节,感谢@KevinCruijssen!

最终将其降低到200以下,所以我现在可以打高尔夫球了:)我最终创建了第二个TIO以根据先前的答案测试事物。

在线尝试!

使这项任务棘手的是:

  • ==不允许使用等于运算符
  • ++不允许增量/赋值运算符
  • All()不允许使用Linq 功能

下面的注释代码:

// anonymous function that takes an IList as input
x=>
  // the first condition makes sure the string even
  // counts of each character
  !x.GroupBy(c=>c).Any(g=>g.Count()%2>0)&
  // the second condition generates all proper substrings of x
  // and tests for any that contain even character counts
  // the string length `l` is repeated `l*l` times
  !Enumerable.Repeat(x.Count,x.Count*x.Count)
    .Where((l,i)=>
      // check that the substring length is greater than 0
      i%l>0&
      // use skip/take to generate a substring
      // and check for a character count thats odd
      // negate the result meaning we have found
      // a substring that invalidates the input
      !x.Skip(i/l).Take(i%l)
        .GroupBy(c=>c).Any(g=>g.Count()%2>0)
    )
    // if any invalid substrings are found
    // then the result in invalid
    // the comment string at the end is needed
    // to make the program well-linked
    .Any()/*>!oyAnC0EmeablR*WhiS/T*/

您可以删除尾随注释中的两个空格。
Kevin Cruijssen

@KevinCruijssen-好一个:)我忘记了我已经添加了一个空格。我不得不把另一个扔进源头。
dana


2

Brachylog,16个字节

sᶠb∋p~j&sᶠb∋p~j&

在线尝试!

false.为真实实例和true.虚假实例打印。TIO版本太慢了,无法自行处理,但是由于它是一个字符串,重复两次,因此具有明显的链接性。

说明

    Input is a string: "abcacbaa"
sᶠ  Find all substrings: ["abcacbaa","abcacba","abcacb",..,"a"]
b   Behead (now the proper substrings remain): ["abcacba","abcacb",..,"a"]
∋   Take one of them: "abcacb"
p   Permute it: "abcabc"
~j  It is some string repeated twice: "abc"
&   Get the input again: "abcacbaa"
    Then repeat the above.
    If the constraints can be satisfied, the result is true, otherwise false.

1

05AB1E22 20 字节

Œε¢Pà}KŒIKεSIS¢ÈP}àÈ

1如果字符串链接正确,或者0字符串链接错误,则输出。

在线尝试验证所有测试用例

说明:

基本程序为ŒsKεsS¢ÈP}à11个字节),0如果链接正确或链接1不正确,则输出。尾随È(is_even)是半无操作的,它会反转输出,因此1对于链接良好的字符串和0未链接良好的字符串而言。其他部分则禁止操作以符合挑战规则。

Œε¢Pà}K         # No-ops: substrings, map, count, product, maximum, close map, remove
                # Due to the last remove, we're back at the (implicit) input again
Œ               # Take the substrings of the input
 IK             # Remove the input itself from that list of substrings
   ε            # Map each substring to:
    S           #  No-op: transform the substring into a list of characters
     IS         #  Get the input-string as a list of characters
       ¢        #  Count the occurrence of each character in the current substring
        È       #  Check which counts are even (1 if truthy; 0 if falsey)
         P      #  Take the product of that
              # After the map: check if any are truthy by taking the maximum
            È   # Semi no-op: check if this maximum is even (0 becomes 1; 1 becomes 0)
                # (and output the result implicitly)
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.