从子字符串中识别字符串


20

介绍

之前,我曾提出过两个 挑战,即如何使用尽可能少的查询类型的操作来重建对象。这将是第三。

任务

您的输入应为S字母abc及其长度上的非空字符串,而您的输出应为S。没有限制,这当然是一件微不足道的任务。问题是您不允许S直接访问。您唯一可以做的S就是调用函数num_occur(T, S),其中T还有其他一些字符串,并num_occur计算Tin 中出现的次数S。重叠事件都算作不同,所以num_occur(T, S)真正返回的指标的数量i,使得

S[i, i+1, …, i+length(T)-1] == T

例如,num_occur("aba", "cababaababb")将返回3。注意也num_occur(S, S)将返回1。的结果num_occur("", S)是不确定的,因此您不应在空字符串上调用该函数。

简而言之,您应该编写一个函数或程序,该函数或程序以Slength(S)作为输入,num_occur对一些较短的字符串进行调用,并S进行多次调用,然后S从该信息中重构并返回它。

规则和计分

您的目标是编写一个尽可能少调用的程序num_occur。在此存储库中,您将找到一个名为的文件abc_strings.txt。该文件包含100个字符串,每个字符串在其各自的行上,长度在50到99之间。您的得分是这些输入上调用num_occur总次数,得分越低越好。您的解决方案最好在运行时跟踪该数字,并在完成后打印出来。通过从中选择均匀随机的字母来生成字符串abc。您可以针对这种生成字符串的方法进行优化,但不能对字符串本身进行优化。

没有时间限制,除了您应该在提交测试案例之前运行您的解决方案。您的解决方案应该适用于任何有效的输入S,而不仅仅是测试用例。

num_occur如果您不使用别人的,也鼓励您也分享自己的实现。为了使事情顺利进行,这是Python中的实现:

def num_occur(needle, haystack):
    num = 0
    for i in range(len(haystack) - len(needle) + 1):
        if haystack[i : i + len(needle)] == needle:
            num += 1
    return num

我们的算法是否必须适用于所有可能的字符串S,还是仅适用于测试用例?
罗夫霍

@Loovjo好问题。从理论上讲,它们应适用于所有非空字符串。我将编辑挑战。
Zgarb

all non-empty strings什么长度?
edc65 '16

从理论上讲,@ edc65。您可以忽略有限的内存地址和其他实际限制。
Zgarb

可以添加VW算法以成功通过评估测试:首先检查abc_strings.txt的已知字符串的发生
Emmanuel

Answers:


6

Javascript,14325 14311调用

我们从一个空字符串开始,然后通过递归方式在当前字符串的末尾或开头添加一个新字母,同时至少还有一个匹配项。

之前的所有结果numOccur()都保存在该sym对象中,我们使用该数据立即拒绝任何不可能的候选新字符串。

编辑:因为我们总是以开头'a',所以我们总是知道a字符串中的确切数字。当我们检测到仅a缺少序列时,我们将使用此信息更早地结束该过程。还修复了在Chrome和IE中无效的正则表达式。

var test = [
  'ccccbcbbbbacbaaababbccaacbccaaaaccbccaaaaaabcbbbab',
  // etc.
];
var call = 0;

function guess(S, len) {
  var sym = {};
  recurse(S, len, "", sym);
  return sym.result;
}

function recurse(S, len, s, sym) {
  var dictionary = [];

  if(s == '' || (isCandidate(s, sym) && (sym[s] = numOccur(S, s)))) {
    if(s.length == len) {
      sym.result = s;
    }
    else if(sym['a'] && count(s, 'a') == sym['a'] - (len - s.length)) {
      dictionary = [ Array(len - s.length + 1).join('a') ];
    }
    else {
      dictionary = [ "a", "b", "c" ];
    }
    dictionary.some(function(e) {
      return recurse(S, len, s + e, sym) || recurse(S, len, e + s, sym);
    });
    return true;
  }
  return false;
}

function isCandidate(s, sym) {
  return sym[s] === undefined && Object.keys(sym).every(function(k) {
    return count(s, k) <= sym[k];
  });
}

function count(s0, s1) {
  return (s0.match(new RegExp(s1, 'g')) || []).length;
}

function numOccur(S, s) {
  call++;
  return count(S, s);
}

test.forEach(function(S) {
  if(guess(S, S.length) != S) {
    console.log("Failed for: '" + S + "'");
  }
});
console.log(call + " calls");

完整的可执行代码段如下。


“简而言之,您应该编写一个函数或程序,以根据该信息重建S并返回它
KarlKastor

@KarlKastor-糟糕。你是对的。那是固定的。谢谢!
Arnauld

4

Python,15205次呼叫

def findS(S, len_s, alphabeth = "abc"):
    if len_s == 0:
        return ""
    current = ""
    add_at_start = True
    while len(current) < len_s:
        worked = False 
        for letter in alphabeth:
            if add_at_start:
                current_new = current + letter
            else:
                current_new = letter + current
            if num_occur(current_new, S) > 0:
                current = current_new
                worked = True
                break
        if not worked:
            add_at_start = False
    return current 

此提交很可能不是最佳选择,因为它仅用于num_occur检查字符串是否是的子字符串S,并且从不使用它来实际计算子字符串的数量。

该算法通过存储一个字符串来工作,该字符串current最终与字符串相等S。这是算法中的所有步骤:

  1. 我们设定current等于''

  2. 浏览字母表中的每个字母,然后执行以下操作:

    2.1。创建一个新字符串current_new,并将其设置为等于,current后跟字母。

    2.2。通过运行它来检查是否current_new包括在内,并查看结果是否大于一。Snum_occur

    2.3。如果current_new包含在中S,请设置currentcurrent_new并返回步骤2。否则,我们转到下一个字母。

  3. 如果的长度current等于的长度,S则可以说我们完成了。否则,我们回到步骤2,但修改步骤2.1,使其current_new等于后跟的字母current。当我们再次到达此步骤时,我们就完成了。


1
Python的for循环具有else子句。这将是一个完美的用例。
雅库布

4

Python 2,14952 14754调用

与第一个答案非常相似,但是不会尝试使用下一个字符,这会导致以下不可能的子字符串:

  • 从中我们知道num_occur它们不会出现在目标中(根据先前的调用)

  • 我们已经多次使用了子字符串,而不是根据 num_occur

(将在一分钟内添加子计数)完成

def get_that_string(h,l,alpha = "abc"):
    dic = {}
    s = ""
    ##costs 1 additional call per example, but its worth it
    char_list = [num_occur(j,h) for j in alpha[:-1]]
    char_list.append(l - sum(char_list))
    for y, z in zip(char_list,alpha):
        dic[z] = y
    end_reached = False
    while len(s) < l:
        for t in alpha:
            if not end_reached:
                neu_s = s + t
                substrings = [neu_s[i:]   for i in range(len(neu_s))]
            else:
                neu_s = t + s
                substrings = [neu_s[:i+1] for i in range(len(neu_s))]
            ## Test if we know that that can't be the next char
            all_in_d = [suff for suff in substrings if suff in dic.keys()]
            poss=all(map(dic.get,all_in_d))
            if poss:
                if not neu_s in dic.keys():
                    dic[neu_s] = num_occur(neu_s,h)
                if dic[neu_s] > 0:
                    s=neu_s
                    for suff in all_in_d:
                        dic[suff] -= 1
                    break
        else:
            end_reached = True
    ##print s
    return s


## test suite start
import urllib

def num_occur(needle, haystack):
    global calls
    calls += 1
    num = 0
    for i in range(len(haystack) - len(needle) + 1):
        if haystack[i : i + len(needle)] == needle:
            num += 1
    return num

calls = 0
url = "https://raw.githubusercontent.com/iatorm/random-data/master/abc_strings.txt"
inputs = urllib.urlopen(url).read().split("\n")
print "Check: ", inputs == map(lambda h: get_that_string(h, len(h)), inputs)
print "Calls: ", calls

4

Python的12705 12632个电话

  1. 列出2个字符串出现的字符串
  2. 排序列表
  3. 先构建最可能的字符的字符串,不要测试是否只有一种可能性
  4. 更新清单
  5. 如果列表为空,则完成,否则执行步骤2

我使用了Loovjo函数骨架。我从不使用Python编写代码,我需要引导程序

编辑:
添加了一个字符长度字符串的
代码添加了代码以拒绝已经匹配的模式

def finds(S):

    if len(S) == 0:
            return ""
    if len(S) == 1 
            if num_occur("a",S) == 1 :
                         return "a"
            if num_occur("b",S) == 1 :
                         return "b"
            return "c"
    tuples=[]
    alphabet=[ "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb"]
    for s in alphabet : tuples.append( (num_occur(s,S), s) )

    sum=0
    for (i,s) in tuples :   sum+=i
    tuples.append( (len(S)-sum-1, "cc") )
    tuples.sort(key=lambda x:(-x[0],x[1]))

    (i, current) = tuples[0]
    tuples[0] = (i-1, current)

    add_at_start = True
    nomatch=[]
    while len(tuples) > 0:
            worked = False
            tuples.sort(key=lambda x:(-x[0],x[1]))
            count=0
            if not add_at_start :
                    for (n, s) in tuples :
                            if s[0]==current[-1:] :         count+=1
            for i in range(len(tuples)):
                    (n, s)=tuples[i]
                    if add_at_start:
                            if current[0] == s[1] :
                                    current_new = s[0] + current
                                    possible=True
                                    for nm in nomatch :
                                            lng=len(nm)
                                            if current_new[0:lng] == nm :
                                                    possible=False
                                                    break
                                    if possible and num_occur(current_new, S) > 0:
                                            current = current_new
                                            worked = True
                                    else :
                                            nomatch.append(current_new)
                    else:
                            if current[-1:] == s[0] :
                                    current_new =  current + s[1]
                                    possible=True
                                    for nm in nomatch :
                                            lng=len(nm)
                                            if current_new[-lng:] == nm :
                                                    possible=False
                                                    break
                                    if count == 1 or (possible and num_occur(current_new, S) > 0) :
                                            current = current_new
                                            worked = True
                                    else :
                                            nomatch.append(current_new)
                    if worked :
                            if n == 1:
                                    del tuples[i]
                            else    :
                                    tuples[i] = (n-1, s)
                            break
            if not worked:
                    add_at_start = False
    return current

您的字母中没有“ cc”?
Sparr

@Sparr“ cc”被计算出来,可以节省100个调用:`tuples.append((len(S)-sum-1,“ cc”))`
伊曼纽尔
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.