最大子串构造


18

在此挑战中,您通过了两件事:

  1. 字符串长度 N
  2. 字符串列表L,每个都有一个指定的点值。任何未传入的字符串的点值为0

您需要构造一个长度字符串N,以使所有子字符串点的总和尽可能大。

例如:

5 [("ABC", 3), ("DEF", 4), ("CDG", 2)]

应该输出

ABCDG

因为带有点(ABCCDG)的两个子字符串总共有5个点,所以其他任何可能的构造都不能给出5个或更多点。

子字符串可以在字符串中多次使用,并且可以重叠。您可以假设这些点将始终为正,子字符串的长度将在1到N字符长之间,并且那个N > 0。如果最多有多个构造,请打印其中任何一个。

您的程序必须在合理的时间内运行(每个示例的时间不得超过一分钟):

1 [("A", 7), ("B", 4), ("C", 100)]     => C
2 [("A", 2), ("B", 3), ("AB", 2)]      => AB
2 [("A", 1), ("B", 2), ("CD", 3)]      => BB
2 [("AD", 1), ("B", 2), ("ZB", 3)]     => ZB
3 [("AB", 2), ("BC", 1), ("CA", 3)]    => CAB
3 [("ABC", 4), ("DEF", 4), ("E", 1)]   => DEF
4 [("A", 1), ("BAB", 2), ("ABCD", 3)]  => AAAA or ABAB or BABA or ABCD
5 [("A", 1), ("BAB", 2), ("ABCD", 3)]  => BABCD or BABAB
5 [("ABC", 3), ("DEF", 4), ("CDG", 2)] => ABCDG
5 [("AB", 10), ("BC", 2), ("CA", 2)]   => ABCAB
6 [("AB", 10), ("BC", 2), ("CA", 2)]   => ABABAB
8 [("AA", 3), ("BA", 5)]               => BAAAAAAA
10 [("ABCDE", 19), ("ACEBD",  18), ("ABEDC", 17), ("BCEDA", 16), ("EBDAC", 15), ("BACD", 14), ("CADB", 13), ("ABDC", 12), ("CABD", 11), ("EBDC", 10), ("ACE", 9), ("CBA", 8), ("AEC", 7), ("BE", 6), ("AE", 5), ("DC", 4), ("BA", 3), ("A", 2), ("D", 1)]
=> ACEBDACEBD

这是一个,所以请用您喜欢的语言准备最短的答案!


我们是否必须使用您的确切输入格式,还是可以为我们的语言使用任何方便的输入格式?
flawr

@flawr任何方便的输入方法都可以(字典,stdin,函数参数)
Nathan Merrill

DEF元组缺少一个逗号
isaacg

我有一个很好的解决方案,但是对于最后一个测试用例来说太慢了。
isaacg 2015年

1
@isaacg我有一个优雅的解决方案,可惜此注释太小而无法包含它。(我没有,只是想引用Fermat。)
Orlp

Answers:


1

Python 2.7,503字节

这不是特别打高尔夫球,也不是特别有效。这只是蛮力强制的可行字符串的相对精简枚举。我认为创建可与A *一起使用的启发式算法不会太困难,这可能会更快一些。不过,我并没有为此而烦恼,因为这种方法可以在笔记本电脑上大约47秒内解决所有示例。

import re
v=lambda l,s:sum([len([m.start() for m in re.finditer('(?=%s)'%u,s)])*v for u,v in l])
def m(n,l,e):
 if len(e)==n:
  yield e
 else:
  u=1
  for s,v in sorted(l,key=lambda j:j[1],reverse=True):
   for i in range(len(s)-1,0,-1):
    if len(e)+len(s)-i <= n and e.endswith(s[:i]):
     for r in m(n,l,e+s[i:]):
      u=0;yield r
   if len(e)+len(s)<=n:
    for r in m(n,l,e+s):
     u=0;yield r
  if u:
   yield e
def p(n,l):
 b,r=-1,0
 for s in m(n,l,''):
  a=v(l,s)
  if a>b:b,r=a,s
 return r

要测试它:

if __name__ == "__main__":
    for n, l in [
            (1, [("A", 7), ("B", 4), ("C", 100)]),     # => C
            (2, [("A", 2), ("B", 3), ("AB", 2)]),      # => AB
            (2, [("A", 1), ("B", 2), ("CD", 3)]),      # => BB
            (2, [("AD", 1), ("B", 2), ("ZB", 3)]),     # => ZB
            (3, [("AB", 2), ("BC", 1), ("CA", 3)]),    # => CAB
            (3, [("ABC", 4), ("DEF", 4), ("E", 1)]),   # => DEF
            (4, [("A", 1), ("BAB", 2), ("ABCD", 3)]),  # => AAAA or ABAB or BABA or ABCD
            (5, [("A", 1), ("BAB", 2), ("ABCD", 3)]),  # => BABCD or BABAB
            (5, [("ABC", 3), ("DEF", 4), ("CDG", 2)]), # => ABCDG
            (5, [("AB", 10), ("BC", 2), ("CA", 2)]),   # => ABCAB
            (6, [("AB", 10), ("BC", 2), ("CA", 2)]),   # => ABABAB
            (8, [("AA", 3), ("BA", 5)]),               # => BAAAAAAA
            (10, [("ABCDE", 19), ("ACEBD",  18), ("ABEDC", 17), ("BCEDA", 16), ("EBDAC", 15), ("BACD", 14), ("CADB", 13), ("ABDC", 12), ("CABD", 11), ("EBDC", 10), ("ACE", 9), ("CBA", 8), ("AEC", 7), ("BE", 6), ("AE", 5), ("DC", 4), ("BA", 3), ("A", 2), ("D", 1)]) # => ACEBDACEBD
    ]:
        print p(n, l)

说明

v函数通过搜索L中所有出现的子字符串来简单地计算给定字符串的值。该m函数枚举所有长度可以由的子字符串生成的n带有前缀e的字符串lm递归调用自己;第一个电话应该传递''e。例如:

>>> for s in m(4, [("A", 1), ("BAB", 2), ("ABCD", 3)], ''):print s
ABCD
BABA
ABCD
ABAB
AAAA

p函数简单地循环遍历所有可能的字符串(由枚举m),并返回具有最高值的字符串(由确定v)。

请注意,该m函数实际上通过基于子字符串的值进行排序来对枚举进行优先级排序。事实证明,这对于确保最佳性是不必要的,并且实际上会稍微影响效率。通过删除它,我可以节省约20个字节。

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.