ระบุสตริงจากสตริงย่อย


20

บทนำ

ก่อนหน้านี้ฉันได้สร้างความท้าทายสอง ประการโดยที่ความคิดคือการสร้างวัตถุขึ้นใหม่โดยใช้การดำเนินการชนิดแบบสอบถามน้อยที่สุดเท่าที่จะทำได้ นี่จะเป็นครั้งที่สาม

งาน

ปัจจัยการผลิตของท่านจะเป็นสตริงที่ไม่ว่างเปล่าSมากกว่าตัวอักษรและความยาวของมันและส่งออกของคุณจะเป็นabc Sไม่มีข้อ จำกัด แน่นอนว่านี่จะเป็นงานที่ไม่สำคัญ การจับคือคุณไม่ได้รับอนุญาตให้เข้าถึงSโดยตรง สิ่งเดียวที่คุณจะได้รับอนุญาตจะทำอย่างไรเพื่อSที่จะเรียกใช้ฟังก์ชันnum_occur(T, S)ที่Tบางสายอื่น ๆ และnum_occurนับจำนวนของการเกิดขึ้นของในT 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)คือไม่ได้กำหนดและคุณไม่ควรเรียกใช้ฟังก์ชันบนสตริงว่าง

ในระยะสั้นคุณควรเขียนฟังก์ชั่นหรือโปรแกรมที่ใช้Sและlength(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

@ Loovjo เป็นคำถามที่ดี ในทางทฤษฎีควรทำงานกับสตริงที่ไม่ว่างทั้งหมด ฉันจะแก้ไขการท้าทาย
Zgarb

all non-empty stringsความยาวเท่าใด?
edc65

@ edc65 ในทางทฤษฎีใช่ คุณสามารถละเว้นที่อยู่หน่วยความจำที่มีขอบเขตและข้อ จำกัด ในทางปฏิบัติอื่น ๆ
Zgarb

เป็นไปได้ที่จะเพิ่มอัลกอริทึม VW เพื่อผ่านการทดสอบการประเมินผลด้วยความสำเร็จ: ตรวจสอบก่อนว่ามีสตริงที่รู้จักกันเป็น abc_strings.txt หรือไม่
Emmanuel

คำตอบ:


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รวมอยู่ในการSทำงานnum_occurกับมันหรือไม่และดูว่าผลลัพธ์มากกว่าหนึ่ง

    2.3 หากcurrent_newจะรวมอยู่ในSตั้งcurrentไปcurrent_newและกลับไปขั้นตอนที่ 2 บ้างที่เราไปที่ตัวอักษรถัดไป

  3. หากความยาวของcurrentเท่ากับความยาวของSเราสามารถพูดได้ว่าเราเสร็จแล้ว มิฉะนั้นเรากลับไปที่ขั้นตอนที่ 2 แต่ปรับเปลี่ยนขั้นตอนที่ 2.1 เพื่อให้current_newเท่ากับตัวอักษรตามมาcurrentแทน เมื่อเรามาถึงขั้นตอนนี้อีกครั้งเราก็จะทำ


1
Python for loop มีประโยคอื่น นี่จะเป็นกรณีการใช้งานที่สมบูรณ์แบบสำหรับมัน
Jakube

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 ฉันต้องการบูทrap

แก้ไข:
เพิ่มรหัสสำหรับสายอักขระยาวหนึ่งตัว
เพิ่มรหัสเพื่อปฏิเสธรูปแบบที่ตรงกันแล้ว

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

ไม่ 'ซีซี' ในตัวอักษรของคุณ?
Sparr

คำนวณ @Sparr "cc" แล้วนั่นจะบันทึกการโทรได้ 100 ครั้ง: `tuples.append ((len (S) -sum-1," cc "))`
Emmanuel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.