可配对的字符串


28

如果字符串可以拆分为子字符串,则该字符串是可配对的,每个子字符串都是连续重复两次的字符串。例如,aabaaababbbaba可配对为:

aaba aaba
b b
ba ba

给定一个非空字符串a“ s”和b“ s”,如果可以配对,则输出True值,如果不是,则输出Falsey值。

可配对:

aa
abaaba
bbababbb
aabaaababbbaba
babababa
bbbbbbbbbbbb
aaababbabbabbbababbaabaabaababaaba
aaaabaab

无法配对:

a
ba
baab
abaabaaba
bbbbbbbbbbbbbbb
baababbabaaaab
aaaaabbaaaaa

我鼓励您提出非基于正则表达式的解决方案,即使您的语言中已经存在较短的正则表达式答案。您可以将它们标记为“ no regex”。正则表达式是指内置的字符串模式匹配子系统。


排行榜:


除了可以使用其他方式ab吗?
暴民埃里克

如果bbababbb是可配对的,为什么baab和aaaaabbaaaaa不能配对?
rnso

@rnso据我了解,bbababbb可以作为3对:bb,abab和bb串接在一起,形成原始字符串,而其他两个不能。
阳光

通过“每个(子字符串)是一个连续两次重复的字符串”这个问题,bbababbb不满意。否则,也可以将baab拆分为baab,并将aaaaabbaaaaa拆分为aaaaa bb aaaaa。
rnso '16

@rnso不确定您的意思。连续来说,我的意思是两个重复是相邻的。在“ baa b”中,两个b被a隔开,因此不起作用。
xnor

Answers:


11

Python 2,68 63字节

f=lambda s,n=1:s==2*s[:n]or''<s[n:]>-f(s,n+1)<f(s[n:])*f(s[:n])

返回TrueFalse。在Ideone上进行测试


4
这是一个非常干净的递归,对双精度中心和分区中心都使用了索引。可笑的是,真实性被检查为小于某物。我确实看到了一些改进...
xnor

8

视网膜,11字节

^((.+)\2)+$

尝试所有测试用例。前两个字节使其成为多行。

就像所有Retina程序一样,对规则进行相当直观的解释,显然使用了正则表达式。


2
Dangit,我一直在等待3个星期才能发布此消息……
ETHproductions'Nov

2
马丁也一直在等
xnor

5
哎呀!我也只击败了他10秒钟...嗯,我敢肯定,如果我写一个六角答案,他会原谅我!
FryAmTheEggman '16

5
@FryAmTheEggman我很期待。:)
Martin Ender's

2
与Perl完全相同:perl -pE '$_=/^((.+)\2)+$/'
Dada

8

果冻,10 字节

ẆŒPẋ€€2F€ċ

效率不高... 在线尝试!

怎么运行的

ẆŒPẋ€€2F€ċ  Main link. Argument: s (string)

Ẇ           Window, generate the array of all substrings of s.
 ŒP         Powerset; generate all subarrays of substrings of s.
   ẋ€€2     Repeat each substring in each subarray twice.
            For example, ["ab", "a", "b"] becomes ["abab", "aa", "bb"].
       F€   Flatten the subarrays by concatenating their strings.
         ċ  Count how many times s appears in the generated strings.

这似乎效率低下。在合理的时间内可以处理多长时间?
John Dvorak

1
这是极其无效的(我认为O(2 ^ n ^ 2))。我必须在当地检查。对于长度为6的字符串,TIO用尽了内存。
丹尼斯,

8
长度为6的字符串在我的计算机上需要3:20分钟,并且需要6 GB的内存。
丹尼斯,

1
@Dennis 那么,我们不要输入100的长度,因为一切都会崩溃。是的,甚至是TIO。
暴民埃里克

@EriktheGolfer这是一个好主意,因为它会不必要地降低TIO的其他用途,但不会使其崩溃。一旦系统内存不足,该过程就会被OOM杀死。
丹尼斯

5

Haskell,72 69字节(无正则表达式)

g(a:b:c)|a==b=g c
g x=x==[]
any(g.words.concat).mapM(\c->[[c],c:" "])

暴力手段。在Ideone上尝试一下

感谢BlackCap提供-3个字节。

说明

helper函数g获取一个字符串列表,并检查它是否由成对的相同字符串组成,例如["aa","aa","bba","bba","ab","ab"]。(匿名)主函数以所有可能的方式分割字符串,并检查至少一个分割结果是否为g可接受的列表。

g(a:b:c)                                  g on list with elements a, b and tail c,
        |a==b                              in the case that a==b,
             =g c                          recurses to the tail c.
g x=                                      g on any other list x
    x==[]                                  checks that x is empty.
                                           This includes the case where a is not equal
                                           to b, resulting in False.
any(g.words.concat).mapM(\c->[[c],c:" "]) The main function:
                    mapM(\c->[[c],c:" "])  Replace each letter c with either "c" or "c "
                                           in all possible ways, return list of results.
any(              ).                       Check that at least one result satisfies this:
            concat                          Concatenate the 1- or 2-letter strings,
      words.                                split again at each space,
    g.                                      apply g.

您可以替换or.mapany
BlackCap

@BlackCap当然,谢谢!我最初有any g.map(words.concat),并认为:“嘿,我可以打高尔夫球的anyor” ...
Zgarb

5

Python 2,60个字节

f=lambda s,t='':''<s>f(s[1:],t+s[0])|f(t and s)*f(t)>-(s==t)

我希望这是正确的。它运行非常缓慢,并且and看起来不是最佳的。


1
我尝试使用字符串,但无法达到基于索引的分数。那是and你那里的一个聪明人。
丹尼斯,

恭喜!在分区上递归是我想到的窍门。
xnor

4

果冻,12 字节

ŒṖµœs€2ZEµ€S

我的其他答案长两个字节,但是这种方法效率更高,可以处理除一个测试用例之外的所有用例。

在线尝试!

怎么运行的

ŒṖµœs€2ZEµ€S  Main link. Argument: s (string)

ŒṖ            Generate all partitions of s.
  µ      µ€   Map the monadic chain between the µ's over the partitions.
   œs€2         Split each string in the partition into two chunks of equal length.
       Z        Zip/transpose, collecting the first halves in one array and the
                second halves in another.
        E       Test the arrays of halves for equality.
           S  Return the sum of the results, counting the number of different
              ways s can be paired.

3

Pyth-无正则表达式-13 12字节

检查是否有任何分区由当被一分为二时彼此相等的所有字符串组成。

sm.AqMcL2d./

测试套件


3

Brachylog,14个字节(无正则表达式)

lye~l:1j@2zcc?

在线尝试!

对于某些测试用例来说,这太慢了

说明

ly                  The list [0, …, length(Input)]
  e~l               A list whose length is an element of the previous list
     :1j            Append itself to this list
        @2zc        Split in half, zip and concatenate so that the list contains pairs of
                      consecutive identical elements
            c?      The concatenation of that list must result in the Input

3

JavaScript(ES6),无正则表达式,75 74字节

f=s=>!s|[...s].some((_,i)=>i&&s[e='slice'](0,i)==s[e](i,i+=i)&&f(s[e](i)))

1否则返回可配对的0。编辑:由于@ edc65,节省了1个字节。


真好!使用相同的计数substr而无需修改i。但是slice重复3次,您可以保存1个字节的别名
edc65 '16

@ edc65如何在不进行修改的情况下获得相同的计数i?我意识到s.substr(i,i+i)返回的结果与相同,s.slice(i,i+=i)i后来我使用了后来的修改后的值...
Neil

s.substr(i,i)减少了2个字节,然后增加了s.slice(i+i)2个字节
edc65

@ edc65哦,当然,我必须喝点咖啡……
Neil

3

Python,58个字节

f=lambda s,p='':s>''and(f(p)>-(s==p)<f(s))|f(s[1:],p+s[0])

这基于Dennis的递归方法。布尔取反技巧也是从那里取来的。

新的想法是(p,s)通过以('',s)的第一个字符开始并将其重复移动s到的最后一个字符来递归原始字符串的分区p。这样就可以直接引用这些部分,而无需进行字符串切片。但是,由于分区从p空开始,因此必须小心避免无限循环的f(s)call f(s)


2

JavaScript(ES6),24个字节

x=>/^((.+)\2)+$/.test(x)

大概不会比这短。


那不是\2吗?
尼尔

@Neil出于某种原因,我认为它可以使用\1,但是aab返回true...感谢您的修复。
ETHproductions's


2

Python,66 64字节

感谢@Zgarb -1个字节!

f=lambda x,s=1:x>x[:s]and(x==2*x[:s])|f(x[:s])&f(x[s:])|f(x,s+1)

返回TrueFalse

在线尝试!

打高尔夫球的任何帮助,将不胜感激。


1

球拍230字节

(let((sl string-length)(ss substring))(if(odd?(sl s))(printf ".~n")(begin(let p((s s))(if(equal? s "")(printf "!")
(for((i(range 1(add1(/(sl s)2)))))(when(equal?(ss s 0 i)(ss s i(* 2 i)))(p(ss s(* 2 i)(sl s)))))))(printf ".~n"))))

打印一个“!” 字符串可配对的每种方式。打印一个“。” 在最后。

取消高尔夫:

(define (f s)
  (let ((sl string-length)                              ; create short names of built-in fns
        (ss substring))
    (if (odd? (sl s))  (printf ".~n")                   ; odd length strings cannot be pairable; end here.
        (begin
          (let loop ((s s))                             ; start testing here
            (if (equal? s "") (printf "!")              ; if no remaining string, it must be pairable
                (for ((i (range 1 (add1 (/(sl s)2)))))  ; ch lengths varying from 1 to half of string length
                  (when (equal? (ss s 0 i)              ; ch if substrings are same
                                (ss s i (* 2 i)))
                    (loop (ss s (* 2 i) (sl s) ))))))   ; if yes, loop to check remaining string.
          (printf ".~n")))))                            ; End of testing.

测试:

(println "Following should be pairable")
(f "bbaabbaa")            ; should produce 2 '!' since 2 ways are possible.
(f "aa")
(f "abaaba")
(f "bbababbb")
(f "aabaaababbbaba")
(f "babababa")                    ; should be pairable in 2 ways.
(f "bbbbbbbbbbbb")                ; should be pairable in many ways.
(f "aaababbabbabbbababbaabaabaababaaba")
(f "aaaabaab")
(println "Following should be unpairable")
; (f "a")
(f "ba")
(f "baab")
(f "abaabaaba")
(f "bbbbbbbbbbbbbbb")
(f "baababbabaaaab")
(f "aaaaabbaaaaa")

输出:

"Following should be pairable"
!!.
!.
!.
!.
!.
!!.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!.
!.
!.
"Following should be unpairable"
.
.
.
.
.
.

1

Perl,16 +2 = 18个字节(使用正则表达式)

-nl标志运行。 -E免费。

say/^((.+)\2)+$/

运行方式:

perl -nlE 'say/^((.+)\2)+$/'

如果可配对,则返回捕获组的列表(真值);如果不可配对,则返回空字符串。

说明

这些-nl标志将在循环(-n)中运行代码,每次将输入(由于删除了尾随换行符-l)放入变量中$_,然后每次输入输入时对代码进行评估,直到手动终止程序为止。该-E标志使您可以在命令行上评估代码,并启用say命令。

say/^((.+)\2)+$/

   /^((.+)\2)+$/  #The regex engine
      (.+)\2      #Find any set of at least one character, followed by itself
     (      )+    #Do this at least one time
   /^         $/  #Make sure that this matches the entire string from start to end
say               #Output the result of the regex

如果找到匹配项(例如,如果字符串可配对),则正则表达式将返回捕获组的列表,其结果为真值,然后将该真值传递给say,并输出。如果未找到匹配项,则正则表达式将返回空字符串,其结果为falsy,然后将其传递给say,并输出。

样品:

$ perl -nlE 'say/^((.+)\2)+$/'
aaababbabbabbbababbaabaabaababaaba
baababaababaaba                      #Truthy
baababbabaaaab
                                     #Falsy
bbababbb
bbb                                  #Truthy
aabaaababbbaba
bababa                               #Truthy
abaabaaba
                                     #Falsy

1

GNU Prolog,49个 46字节

可能也可以在其他变体中使用,尽管它们并非都以相同的方式表示字符串。对于此问题,GNU Prolog的表示形式很有用。

尚不清楚这是否算作使用正则表达式。它没有使用任何类似于regex的功能,但是语言的整个语义与regex相似。

新版本(使用在其他答案中看到的递归技巧):

s(X):-append(A,B,X),(A=B;A\=X,B\=X,s(A),s(B)).

旧版本:

s(X):-X=[];append(A,B,X),B\=X,append(C,C,A),s(B).

这是称为的谓词(Prolog等同于函数)s,而不是完整的程序。像这样使用它:

| ?- s("aa").
true ?
yes
| ?- s("aaababbabbabbbababbaabaabaababaaba").
true ?
yes
| ?- s("baababbabaaaab").
no
| ?- s("bbbbbbbbbbbbbbb").
no

旧解决方案的一个有趣功能是,如果您问口译员“还有更多解决方案吗?” 通过;true ?提示符处使用(而不是像我在上面那样通过在提示符处按return来询问“是否有解决方案”),它返回“ true”的次数等于表示字符串的不同方式的次数以给定的形式(例如,它使用两次返回“ true” s("aaaa").,因为可以将其解析为(a a)(a a)(aa aa))。

Prolog的程序往往是可逆的(允许s生成字符串列表与给定的属性)。较旧的不是(进入无限循环),但这是因为我使用高尔夫方法来确保C为非空。如果您重写程序以将C显式指定为非空,则它将生成格式为“ aa”,“ aabb”,“ aabbcc”等的字符串(Prolog为Prolog,它没有为构成它们的字符指定身份,只是说明哪些字符相同)。较新的将生成形式为“ aa”,“ abab”,“ abcabc”等的字符串;这本身就是一个无限循环,因此永远不会由于无法检测到零长度字符串而到达死点。


1

Brainfuck,177字节

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

格式:

+[<<<<,]
>>>>
[
  >+
  [
    >+
    [
      [>>]
      <+<[<<]
      >+>-
    ]
    <[>+<-]>
    >>,>>[>>]
    +<<[<+> >-<-]
    <[>+<-]>
    >
    [
      not equal
      ,>[-<<<<]
      <[<<<<]
      >
    ]
    <
    [
      equal
      [<<]
      >
    ]
    >>
  ]
  >>
  [
    mismatch
    [>+>>>]
    >>>[>]
    <<<<
    [
      backtrack
      >+[-<<<,<]
      <
      [
        not done yet
        <<<
        [
          [<<<<]
          >>
        ]
        <
      ]
      >
    ]
    >>
  ]
  <
  [
    match
    [->>>>]
    >>[<]
    <
  ]
  <<
]
<.

期望输入时没有尾随换行符。打印\x00为false和\x01true。

在线尝试。

这实现了深度优先搜索。特别是:检查从当前后缀开始的长度增加的重复前缀,如果找到匹配项,则移至下一个后缀,否则返回。

在开始时,将字符串颠倒,并\x01在末尾放置一个前哨。

磁带分为4个单元。节点的内存布局为:

c h x 0

where c是字符,h是用于标识该字符是否在重复前缀的前半部分中x的标志,并且是用于跟踪当前正在比较的一对字符的标志。该h标志留在原地,而x标志形成的移动窗口。

如果字符串是可配对的,则指针将在主循环末尾降落在前哨旁边;否则,指针在回溯时会从字符串的左侧掉落。


1

Brachylog,5个字节

~c~jᵐ

在线尝试!

请注意,由于该算法会检查输入字符串的每个可能分区,因此可能会花费长时间,尤其是在错误情况下。

说明

~c     Reversed concatenate: find a list that, when concatenated, results in the input string
       This examines all partitions of the input
  ~jᵐ  Map reversed juxtapose: for each string in that list, is it the result of concatenating
       a string to itself?

对于像输入字符串"ababcc"~c尝试不同的分区,直到它来到["abab", "cc"],在这一点~j成功的名单中,这两个项目的输出["ab", "c"]和谓词成功。


1

R,31个字节

grepl("^((.+)\\2)+$",scan(,""))

在线尝试!

基于视网膜的答案。

R,129字节

这是原始的非正则表达式答案:

o=(y=utf8ToInt(scan(,"")))<0;for(i in 2*1:(sum(y>0)/2))for(j in 1:(i/2)){w=i:(i-j+1);v=w-j;if(all(y[w]==y[v]))o[c(v,w)]=T};all(o)

在线尝试!


0

Lithp,57个字符

#S::((? (!= (null) (match S "^((.+)\\2)+$")) true false))

用法示例:

% pairable_strings.lithp
(
    (def f #S::((? (!= (null) (match S "^((.+)\\2)+$")) true false)))
    (print (f "aa"))
    (print (f "aabaaababbbaba"))
    (print (f "aaababbabbabbbababbaabaabaababaaba"))
    (print (f "ba"))
)

# ./run.js pairable_strings.lithp
AtomValue { value: 2, type: 'Atom', name: 'true' }
AtomValue { value: 2, type: 'Atom', name: 'true' }
AtomValue { value: 2, type: 'Atom', name: 'true' }
AtomValue { value: 3, type: 'Atom', name: 'false' }
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.