Bir dizeyi alt dizelerinden tanımlama


20

Giriş

Daha önce fikrin mümkün olduğunca az sorgu tipi işlem kullanarak bir nesneyi yeniden oluşturmak olduğu iki zorluk yarattım ; bu üçüncü olacak.

Görev

Girdileriniz Salfabe abcve uzunluğu boyunca boş olmayan bir dize ve çıktınız olacaktır S. Kısıtlama olmaksızın, bu elbette önemsiz bir görev olacaktır; yakalama, Sdoğrudan erişmenize izin verilmemesidir . Eğer yapmak izin konum tek şey Sişlevini çağırmak için ise num_occur(T, S), Tdiğer bazı dize ve num_occuryineleme sayısını sayar Tiçinde S. Çakışan oluşumları ayrı olarak sayılır, böylece num_occur(T, S)çok endeksleri sayısını verir i, öyle ki

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

Örneğin, num_occur("aba", "cababaababb")geri döner 3. Ayrıca num_occur(S, S)geri döneceğini unutmayın 1. Sonucu num_occur("", S)tanımsız olduğunu ve boş bir dize üzerinde işlevini çağırmalıdır değil.

Kısacası, girdi alan Sve length(S)girdi olarak, num_occurdaha kısa dizeleri ve Sbirkaç kez çağıran , Sbu bilgilerden yeniden yapılanan ve döndüren bir işlev veya program yazmalısınız .

Kurallar ve puanlama

Amacınız num_occurmümkün olduğunca az çağrı yapan bir program yazmaktır . Gelen bu depo , sen adlı bir dosya bulacaksınız abc_strings.txt. Dosya, her biri kendi satırında, 50 ve 99 uzunlukları arasında 100 dize içerir. Skorunuz, bu girişlerde yapılan toplam çağrı sayısıdırnum_occur , daha düşük puan daha iyidir. Çözümünüz tercihen bu sayıyı çalışır durumda takip eder ve bitirdikten sonra yazdırır. Dizeler, rasgele rastgele harfler seçilerek oluşturulur abc; bu dizeleri oluşturma yöntemi için optimizasyon yapmanıza izin verilir, ancak dizelerin kendileri için değil .

Çözümünüzü göndermeden önce test senaryolarında çalıştırmanız dışında bir zaman sınırı yoktur. Çözümünüz Syalnızca test senaryoları için değil, geçerli herhangi bir giriş için çalışmalıdır .

num_occurBaşka birini kullanmıyorsanız, uygulamanızı da paylaşmanız teşvik edilir . Topu yuvarlamak için Python'da bir uygulama:

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

Algoritmalarımızın tüm olası dizeler Siçin mi yoksa sadece test senaryoları için mi çalışması gerekiyor?
Loovjo

@Loovjo Güzel soru. Teorik olarak boş olmayan tüm dizeler için çalışmalıdırlar. Meydan okumayı düzenleyeceğim.
Zgarb

all non-empty stringsHangi uzunlukta olursa olsun?
edc65

@ edc65 Teorik olarak evet. Sınırlı bellek adreslerini ve diğer pratik sınırlamaları göz ardı edebilirsiniz.
Zgarb

Değerlendirme testini başarılı bir şekilde geçmek için bir VW algoritması eklemek mümkündür: Önce bilinen abc_strings.txt dizelerinin oluşumunu kontrol edin
Emmanuel

Yanıtlar:


6

Javascript, 14325 14311 çağrı

Boş bir dize ile başlıyoruz ve en azından bir eşleşmemize rağmen mevcut dizenin sonuna veya sonuna yeni bir harf ekleyerek tekrar tekrar yolumuza devam ediyoruz.

Kaynağındaki tüm önceki sonuçlar nesneye numOccur()kaydedilir symve bu verileri, muhtemelen aday olamayacak yeni dizeleri reddetmek için kullanırız.

EDIT : Her zaman ile başladığımız için 'a', her zaman adizenin tam sayısını biliyoruz . Bu bilgiyi, yalnızca bir dizinin aeksik olduğunu tespit ettiğimizde işlemi daha erken bitirmek için kullanırız . Ayrıca Chrome ve IE'de geçersiz olan normal ifade düzeltildi.

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");

Aşağıda tam yürütülebilir snippet.


"Kısacası, [...], S'yi bu bilgilerden yeniden yapıp döndüren bir işlev veya program yazmalısınız ."
KarlKastor

@KarlKastor - Hata. Haklısın. Bu düzeltildi. Teşekkürler!
Arnauld

4

Python, 15205 çağrı

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 

Bu gönderim büyük olasılıkla yetersizdir, çünkü yalnızca num_occur bir dizenin alt dizesi olup olmadığını kontrol etmekS ve bunu hiçbir zaman alt dizelerin miktarını saymak için kullanmaz.

Algoritma current, eşit olacak şekilde oluşturulmuş bir dizeyi saklayarak çalışırS , sonunda . Algoritmadaki tüm adımlar şunlardır:

  1. Ayarladık currentEşit olarak''

  2. Alfabedeki her harfi inceleyin ve aşağıdakileri yapın:

    2.1. Yeni bir dize oluşturun current_newvecurrent bu harfin başına gelecek şekilde harfi ayarlayın.

    2.2. Olmadığını kontrol edin current_newdahildirSnum_occurÜzerinde çalışarak ve sonucun birden büyük olup olmadığını görün.

    2.3. Eğer current_newdahildir S, set currentiçincurrent_new ve adım Else 2. dönmek, biz sonraki harfe gidin.

  3. Uzunluğuna currenteşitse, bittiğimizi Ssöyleyebiliriz. Aksi current_newtakdirde , 2. adıma dönüyoruz, ancak 2.1 harfini değiştirerek harfin ardından gelen harfi eşitleyeceğiz current. Bu adıma tekrar ulaştığımızda işimiz bitti.


1
Python for for loop'un başka bir cümlesi vardır. Bu onun için mükemmel bir kullanım durumu olurdu.
Jakube

4

Python 2, 14952 14754 çağrı

İlk cevaba çok benzer, ancak imkansız alt dizelerle sonuçlanan sonraki karakterleri denemez:

  • num_occurhedefte gerçekleşmediklerini biliyoruz (önceki aramalardan)

  • alt dizeyi halihazırda olduğundan daha sık kullandık num_occur

(bir dakika içinde alt dizelerin sayımını ekler) tamamlandı

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 çağrıları

  1. 2 karakter dizesi oluşumlarının bir listesini yapın
  2. listeyi sırala
  3. önce en olası karakteri deneyen dizgiyi inşa et, sadece bir olasılık olup olmadığını test etme
  4. listeyi güncelle
  5. eğer liste boşsa bitmiş olur diğer adım 2

Loovjo fonksiyon iskeletini kullandım. Python'da kod yazmam bir botçuya ihtiyacım vardı

EDIT:
Bir karakter uzunluğu dizeleri için
kod eklendi Zaten eşleşen desenleri reddetmek için kod eklendi

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

alfabenizde 'cc' yok mu?
Sparr

@Sparr "cc" hesaplanır, bu 100 arama kaydeder: `tuples.append ((len (S) -sum-1," cc "))`
Emmanuel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.