Xác định một chuỗi từ các chuỗi con của nó


20

Giới thiệu

Trước đây tôi đã tạo ra hai thách thức trong đó ý tưởng là tái cấu trúc một đối tượng bằng cách sử dụng càng ít thao tác loại truy vấn càng tốt; đây sẽ là thứ ba

Nhiệm vụ

Đầu vào của bạn sẽ là một chuỗi không trống Strên bảng chữ cái abcvà độ dài của nó, và đầu ra của bạn sẽ là S. Không có hạn chế, điều này tất nhiên sẽ là một nhiệm vụ tầm thường; Điều hấp dẫn là bạn không được phép truy cập Strực tiếp. Điều duy nhất bạn được phép làm gì để Slà để gọi hàm num_occur(T, S), nơi Tmột số chuỗi khác, và num_occurđếm số lần xuất hiện của Ttrong S. Sự xuất hiện chồng chéo được tính là khác biệt, vì vậy num_occur(T, S)thực sự trả về số lượng chỉ số isao cho

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

Ví dụ, num_occur("aba", "cababaababb")sẽ trở lại 3. Cũng lưu ý rằng num_occur(S, S)sẽ trở lại 1. Kết quả num_occur("", S)là không xác định và bạn không nên gọi hàm trên một chuỗi trống.

Nói tóm lại, bạn nên viết một hàm hoặc chương trình nhận Slength(S)làm đầu vào, gọi num_occurmột số chuỗi ngắn hơn và Smột số lần, tái tạo lại Stừ thông tin đó và trả về nó.

Quy tắc và tính điểm

Mục tiêu của bạn là viết một chương trình thực hiện càng ít cuộc gọi num_occurcàng tốt. Trong kho lưu trữ này , bạn sẽ tìm thấy một tập tin gọi là abc_strings.txt. Tệp chứa 100 chuỗi, mỗi chuỗi trên một dòng riêng, trong khoảng từ 50 đến 99. Điểm của bạn là tổng số cuộc gọi đến num_occurcác đầu vào này , điểm thấp hơn sẽ tốt hơn. Giải pháp của bạn tốt nhất là theo dõi số này khi nó chạy, và in nó sau khi hoàn thành. Các chuỗi được tạo bằng cách chọn các chữ cái ngẫu nhiên thống nhất từ abc; bạn được phép tối ưu hóa cho phương thức tạo chuỗi này, nhưng không được phép tạo chuỗi.

Không có giới hạn thời gian, ngoại trừ việc bạn nên chạy giải pháp của mình trên các trường hợp thử nghiệm trước khi gửi nó. Giải pháp của bạn nên hoạt động cho bất kỳ đầu vào hợp lệ S, không chỉ các trường hợp thử nghiệm.

Bạn cũng được khuyến khích chia sẻ việc thực hiện của mình num_occur, nếu bạn không sử dụng người khác. Để bắt đầu, đây là một triển khai trong 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

Các thuật toán của chúng tôi có phải làm việc cho tất cả các chuỗi có thể S, hoặc chỉ cho các trường hợp thử nghiệm không?
Loovjo

@Loovjo Câu hỏi hay. Về lý thuyết họ nên làm việc cho tất cả các chuỗi không trống. Tôi sẽ chỉnh sửa thử thách.
Zgarb

all non-empty stringscó độ dài bao nhiêu?
edc65

@ edc65 Về mặt lý thuyết có. Bạn có thể bỏ qua các địa chỉ bộ nhớ bị ràng buộc và các hạn chế thực tế khác.
Zgarb

Có thể thêm thuật toán VW để vượt qua bài kiểm tra đánh giá thành công: Trước tiên hãy kiểm tra sự xuất hiện của chuỗi abc_strings.txt đã biết
Emmanuel

Câu trả lời:


6

Javascript, 14325 14311 cuộc gọi

Chúng tôi bắt đầu với một chuỗi trống và đi theo cách đệ quy bằng cách thêm một chữ cái mới ở cuối hoặc ở đầu chuỗi hiện tại trong khi chúng tôi vẫn còn ít nhất một trận đấu.

Tất cả các kết quả trước đó numOccur()được lưu trong symđối tượng và chúng tôi sử dụng dữ liệu này để từ chối ngay lập tức bất kỳ chuỗi mới nào không thể là ứng cử viên.

EDIT : Bởi vì chúng tôi luôn bắt đầu 'a', chúng tôi luôn biết chính xác số lượng atrong chuỗi. Chúng tôi sử dụng thông tin này để kết thúc quá trình sớm hơn khi chúng tôi phát hiện ra rằng chỉ thiếu một chuỗi a. Đồng thời sửa lỗi biểu thức chính quy không hợp lệ trong Chrome và 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");

Đoạn mã thực thi đầy đủ bên dưới.


"Nói tóm lại, bạn nên viết một hàm hoặc chương trình [...], tái tạo lại S từ thông tin đó và trả về nó ."
KarlKastor

@KarlKastor - Rất tiếc. Bạn đúng. Điều đó đã được sửa. Cảm ơn!
Arnauld

4

Python, 15205 cuộc gọi

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 

Đệ trình này rất có thể là tối ưu, bởi vì nó chỉ sử dụng num_occurđể kiểm tra xem một chuỗi có phải là một chuỗi con Shay không và nó không bao giờ sử dụng nó để thực sự đếm số lượng chuỗi con.

Thuật toán hoạt động bằng cách lưu trữ một chuỗi currentđược xây dựng tương đương với Scuối cùng. Dưới đây là tất cả các bước trong thuật toán:

  1. Chúng tôi đặt currentbằng''

  2. Đi qua từng chữ cái trong bảng chữ cái và làm như sau:

    2.1. Tạo một chuỗi mới current_newvà đặt nó bằng với currentchữ cái theo sau.

    2.2. Kiểm tra nếu current_newđược bao gồm trong Sbằng cách chạy num_occurtrên nó và xem nếu kết quả lớn hơn một.

    2.3. Nếu current_newđược bao gồm trong S, đặt currentthành current_newvà quay lại bước 2. Khác, chúng ta đi đến chữ cái tiếp theo.

  3. Nếu độ dài currentbằng với chiều dài của Schúng ta có thể nói rằng chúng ta đã hoàn thành. Khác, chúng tôi quay lại bước 2, nhưng sửa đổi bước 2.1 để thay thế current_newbằng chữ cái theo sau current. Khi chúng ta đạt được bước này một lần nữa, chúng ta đã hoàn thành.


1
Python for for loop có một mệnh đề khác. Đây sẽ là một trường hợp sử dụng hoàn hảo cho nó.
Jakube

4

Cuộc gọi Python 2, 14952 14754

Rất giống với câu trả lời đầu tiên, nhưng không thử các ký tự tiếp theo dẫn đến các chuỗi con không thể:

  • chúng tôi biết num_occurrằng chúng không xảy ra trong mục tiêu (từ các cuộc gọi trước)

  • chúng tôi đã sử dụng chuỗi con thường xuyên hơn nó xảy ra theo num_occur

(sẽ bổ sung đếm của chuỗi con trong một phút) thực hiện

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

Cuộc gọi Python 12705 12632

  1. lập danh sách xuất hiện 2 chuỗi ký tự
  2. sắp xếp danh sách
  3. trước tiên hãy xây dựng chuỗi thử ký tự có thể xảy ra nhất, đừng kiểm tra nếu chỉ có một khả năng
  4. cập nhật danh sách
  5. nếu danh sách trống thì kết thúc bước 2

Tôi đã sử dụng bộ xương chức năng Loovjo. Tôi không bao giờ viết mã bằng Python Tôi cần một bootrap

EDIT:
Đã thêm mã cho một chuỗi độ dài ký tự
Đã thêm mã để từ chối các mẫu đã khớp

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

không có 'cc' trong bảng chữ cái của bạn?
Sparr

@Sparr "cc" được tính toán, giúp tiết kiệm 100 cuộc gọi: `tuples.append ((len (S) -sum-1," cc "))`
Emmanuel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.