Liệt kê các sơ đồ vần


26

Một "chương trình vần" là một chuỗi các chữ cái ađể z, như vậy mà lần xuất hiện đầu tiên của các nhân vật trong thứ tự tăng dần (không có khoảng trống), bắt đầu từ a. Ví dụ: với lần xuất hiện đầu tiên được đánh dấu):

abccdbebdcfa
^^^ ^ ^   ^

Số lượng các sơ đồ vần có độ dài Nđược cho bởi số Bell B(N) . ( OEIS A000110 )

Các thách thức

Nhiệm vụ của bạn là thực hiện một phép liệt kê các sơ đồ vần này, tức là ánh xạ phỏng đoán từ số nguyên sang sơ đồ vần. Bạn được cung cấp một số nguyên dương N <= 26, cũng như một số nguyên không âm 0 <= i < B(N). Ngoài ra, bạn có thể sử dụng phạm vi 1 <= i <= B(N). Bạn nên đưa ra một sơ đồ vần có độ dài N, sao cho mỗi ichuỗi mang lại một chuỗi khác nhau.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả qua tham số STDOUT (hoặc thay thế gần nhất), tham số trả về hàm hoặc tham số hàm (out).

Bạn có thể sử dụng chữ thường hoặc chữ in hoa (nhất quán).

Mã của bạn phải có khả năng xử lý bất kỳ đầu vào hợp lệ nào trong khoảng thời gian hợp lý (ví dụ: không quá vài giờ trong N = 26trường hợp xấu nhất i). Điều này sẽ cho phép các giải pháp mở rộng theo cấp số nhân với N(đối với các cơ sở nhỏ), ngay cả trong các ngôn ngữ chậm nhưng cấm các giải pháp mở rộng tuyến tính với i(nghĩa là B(N)). Cụ thể, điều đó có nghĩa là bạn không thể chỉ lặp đi lặp lại qua tất cả các lược đồ vần có độ dài hợp lệ Ncho đến khi bạn loại bỏ các ilược đồ.

Luật tiêu chuẩn được áp dụng.

Ví dụ

Việc gán chính xác các ilược đồ (tức là thứ tự của các lược đồ cho trước N) tùy thuộc vào bạn. Nhưng giả sử bạn đã chọn thứ tự từ điển, giải pháp của bạn sẽ tương ứng với bảng sau (với -biểu thị đầu vào không hợp lệ):

N\i 1    2    3    4    5    6    7    8    9    10   11   12   13   14   15
1   a    -    -    -    -    -    -    -    -    -    -    -    -    -    -
2   aa   ab   -    -    -    -    -    -    -    -    -    -    -    -    -
3   aaa  aab  aba  abb  abc  -    -    -    -    -    -    -    -    -    -
4   aaaa aaab aaba aabb aabc abaa abab abac abba abbb abbc abca abcb abcc abcd

Dưới đây là một tập lệnh CJam ngắn tạo ra tất cả các lược đồ vần hợp lệ cho bất kỳ độ dài nhất định nào (nhưng đừng thử nhiều hơn 10 hoặc bạn sẽ đợi một lúc).

Những thách thức liên quan


5
Tôi có thể đặt tiền thưởng vào một giải pháp thời gian đa thức (được chơi tốt N), với điều kiện là nó không quá tầm thường và tôi quá ngu ngốc khi tìm thấy nó.
Martin Ender

Mặc dù tiền thưởng dành cho các giải pháp thời gian đa thức, tôi vẫn muốn xem các giải pháp thời gian theo cấp số nhân đáp ứng giới hạn thời gian. (Việc triển khai tham chiếu Mathicala của riêng tôi hiện tại vẫn sẽ chiến thắng thử thách.)
Martin Ender

B (26) là số Chuông nhỏ nhất không khớp với số nguyên 64 bit. Nghĩa là :-(
Anders Kaseorg

Câu trả lời:


3

CJam, 68 66 byte

r~:W)1a*{__(;\);_,,.*.+}W(*r~{X@\=_2$\/:CX<!{X:C):X;}&C*-C'a+o}W*;

Hãy thử trực tuyến.

Đây là chương trình CJam đầu tiên của tôi. Nó bắt đầu cuộc sống như một cổng của giải pháp Perl của tôi và ban đầu dài hơn 130 byte. Đề nghị chơi golf hơn nữa được chào đón.

Như với chương trình Perl của tôi, nó gồm hai phần.

Part 1:
r~:W                                         | Read the first input (n) and store it in W
    )1a*                                     | Create an array of n+1 1s
        {              }W(*                  | Repeat n-1 times:
         __                                  | Duplicate array twice
           (;\);                             | Remove first element of 1st array. Swap
                                             | arrays. Remove last element of 2nd array
                _,,                          | Duplicate array. Count items. Create range
                   .*.+                      | Multiply arrays. Add 1st array to result

Part 2:
r~                                           | Read the second input (i)
   {                                  }W*    | Repeat n times:
    X@                                       | Push y (initially 1). Bring item 2 (last array) to top
     \=                                      | Swap top two items. Pop array[y] (v)
       _2$                                   | Duplicate v. Copy item 2 (i) to top
          \/:CX                              | Swap i & v. i/v. Store in C (c). Push y
               <!{       }&                  | If !(i/v < c):
                  X:C):X;                    | c = y. ++y (store in X)
                           C*-C'a+o          | i -= c * v. Push y. Push "a". Add c. Print
                                         ;   | Discard top item (integer 0)

Để gỡ lỗi các mảng được tạo bởi Phần 1, thêm ]_`o~vào giữa Phần 1 & 2. Nếu n là 5, các mảng sẽ trông như thế này : [[1 1 1 1 1 1] [1 2 3 4 5] [2 5 10 17] [5 15 37] [15 52]]. 0 chỉ số của mỗi mảng không được sử dụng, chúng chỉ làm cho nó dễ dàng hơn bằng cách không phải tính toán bù đắp. Các mảng được tính như thế này:

[2 5 10 17] [2 5 10 17] [2 5 10 17]        | Duplicate twice
[2 5 10 17] [2 5 10 17] [5 10 17]          | Discard first item of array
[2 5 10 17] [5 10 17] [2 5 10 17]          | Swap last two arrays
[2 5 10 17] [5 10 17] [2 5 10]             | Discard last item of array
[2 5 10 17] [5 10 17] [2 5 10] [2 5 10]    | Duplicate array
[2 5 10 17] [5 10 17] [2 5 10] 3           | Count items in array
[2 5 10 17] [5 10 17] [2 5 10] [0 1 2]     | Integer to range 0 - n-1
[2 5 10 17] [5 10 17] [0 5 20]             | Multiply arrays [2*0 5*1 10*2]
[2 5 10 17] [5 15 37]                      | Add arrays [5+0 10+5 17+20]

Nó giữ một bản sao của mảng cũ trong khi tính toán cái tiếp theo. Các mảng được đọc và loại bỏ theo thứ tự ngược lại bởi Phần 2.


13

Con trăn 2, 153

u=[1]*999;i=60;exec"u[i]=i%30*u[i-30]+u[i-29];i+=1;"*900
def x(l,n,a=0):m=u[30*l+a];c=n>=a*m;return'.'*l and chr(65+min(n/m,a))+x(l-1,[n%m,n-m*a][c],a+c)

Nó sử dụng thứ tự chữ cái và lập chỉ mục dựa trên 0.

Hãy lbiểu thị độ dài của một hậu tố của các chữ cái và abiểu thị số lượng chữ cái riêng biệt được sử dụng trong phần trước. Sau đó, một hàm p(l,a)tính toán số cách để chọn các chữ cái còn lại có thể là 40 byte:

p=lambda l,a:l<1or a*p(l-1,a)+p(l-1,a+1)

Tuy nhiên, điều này là quá chậm cho thử thách, vì vậy thay vào đó các giá trị cần thiết được tính toán trước và được lưu trữ trong umảng. Ở mỗi giai đoạn tính toán, nếu chữ cái tiếp theo là một trong những chữ cái ađã được sử dụng, thì n = k * p (l - 1, a) + n ' trong đó k là chữ cái 0 được lập chỉ mục của bảng chữ cái và n' là giá trị của nlệnh gọi hàm tiếp theo chứa thông tin về các chữ cái còn lại. Nếu một chữ cái mới được sử dụng, thì n = a * p (l - 1, a) + n ' .


1
Mất bao lâu cho trường hợp đầu vào tồi tệ nhất?
Michael Klein

1
@MichaelKlein Một lượng thời gian không đáng kể.
frageum

Đây chính xác là những gì tôi đã dự định làm (ngoại trừ tôi sẽ thực hiện nó với JS). Công việc tốt! +1
Sản phẩm điện tử

11

Haskell (GHC 7.10), 150 byte

s=(1,\_->[]):s
k!((y,b):l@((x,a):_))|let h i|i<x=k:a i|(p,q)<-divMod(i-x)y=p:b q=(x+k*y,h):(k+1)!l
n#i=(['a'..]!!).fromEnum<$>snd(iterate(0!)s!!n!!0)i

Toán tử n # itính toán isơ đồ vần thứ (không có chỉ mục) về độ dài n. Nó chạy trong các hoạt động O (n²) (số nguyên lớn), tận dụng danh sách vô hạn lười biếng của Haskell để ghi nhớ tự động. Chạy mẫu:

*Main> 26 # 0
"abcdefghijklmnopqrstuvwxyz"
*Main> 26 # 1
"abcdefghijklmnopqrstuvwxya"
*Main> 26 # 2
"abcdefghijklmnopqrstuvwxyb"
*Main> 26 # 49631246523618756271
"aaaaaaaaaaaaaaaaaaaaaaaabb"
*Main> 26 # 49631246523618756272
"aaaaaaaaaaaaaaaaaaaaaaaaab"
*Main> 26 # 49631246523618756273
"aaaaaaaaaaaaaaaaaaaaaaaaaa"
*Main> [1 # i | i <- [0..0]]
["a"]
*Main> [2 # i | i <- [0..1]]
["ab","aa"]
*Main> [3 # i | i <- [0..4]]
["abc","aba","abb","aab","aaa"]
*Main> [4 # i | i <- [0..14]]
["abcd","abca","abcb","abcc","abac","abaa","abab","abbc","abba","abbb","aabc","aaba","aabb","aaab","aaaa"]

(Nếu N tối đa là 25 thay vì 26, .fromEnumcó thể bị xóa, vì B (25) phù hợp với 64 bit Int.)


1
Trông rất tuyệt. Bạn có phiền khi thêm một phiên bản ít chơi gôn để dễ dàng mò mẫm hơn không?
Michael Klein

4

Perl 257 + 1 (cờ -p) = 258

Perl 182 + 10 (cờ -pMbignum) = 192

($n,$i)=split;@m=[@a=(1)x($n+1)];while($a[2]){push@m,[@a=map{$a[$_]*$_+$a[$_+1]}0..$#a-1]}$_='';$y=1;while($w=pop@m){$c=int($i/($v=$$w[$y]));$c=$y++if($c>=$y);$i-=$c*$v;$_.=chr$c+65}

Cảm ơn dev-nul vì đã tiết kiệm nhiều byte! Bây giờ tôi đã viết lại nó dựa trên những gì tôi học được khi thực hiện phiên bản CJam.

Tính toán vần theo thứ tự chữ cái tăng dần, 0 được lập chỉ mục.

Hai phần: Phần 1 là 128 90 byte và tính toán một ma trận cho Phần 2. Phần 2 là 129 92 byte và thực hiện một số phép toán đơn giản để tính toán từng chữ cái. Nếu tôi có thể thoát khỏi ma trận và thay thế nó bằng hai số đơn giản, tôi có thể tính toán một đường dẫn duy nhất thông qua ma trận cho mỗi số và tiết kiệm rất nhiều byte! Rõ ràng, ý tưởng đó không hiệu quả!

Thật không may, nó không tạo ra các vần đúng cho các giá trị icao hơn 9007199254740992, nhưng nó hoạt động rất đẹp với các giá trị thấp! Tôi đã thêm thư viện Bignum với chi phí 11 byte. Nó chạy từ dòng lệnh với perl -pMbignum bell-rhyme.pl. -pMbignum = 10 byte. Nó cũng rất nhanh cho bất kỳ giá trị đầu vào.


2

Oracle SQL 11.2, 412 284 283 byte

WITH a AS(SELECT CHR(96+LEVEL)d,LEVEL b FROM DUAL CONNECT BY LEVEL<=:i),v(s,c,n)AS(SELECT d,1,1 FROM a WHERE b=1 UNION ALL SELECT s||d,b,LENGTH(REGEXP_REPLACE(s||d,'([a-z])\1+','\1'))FROM v,a WHERE(b<=n OR b=c+1)AND LENGTH(s)<:n)SELECT s FROM v WHERE:n=LENGTH(s)AND:i<=:n ORDER BY 1;

Thật không may, nó chỉ chạy tối đa 8. Bất kỳ giá trị lớn hơn nào dẫn đến: ORA-01361: kết quả của chuỗi nối quá dài

Không chơi gôn

WITH a AS(SELECT CHR(96+LEVEL)d,LEVEL b FROM DUAL CONNECT BY LEVEL<=:i),
v(s,c,n) AS
(
  SELECT d,1,1 FROM a WHERE b=1
  UNION ALL
  SELECT s||d,b,LENGTH(REGEXP_REPLACE(s||d,'([a-z])\1+','\1')) 
  FROM v,a 
  WHERE (b<=n OR b=c+1) AND LENGTH(s)<:n
)
SELECT s FROM v WHERE LENGTH(s)=:n AND :i<=:n ORDER BY 1;

Một khung nhìn tạo ra: i chữ cái trong cột a và giá trị của chúng trong b.

Khung nhìn đệ quy v lấy chuỗi đang được xây dựng làm tham số v, giá trị của chữ cái cuối cùng được sử dụng trong c và giá trị của chữ cái lớn nhất được sử dụng trong n. Tham số n bằng độ dài của chuỗi mà không có bất kỳ chữ cái trùng lặp nào, đó là những gì regex dành cho.

Một chữ cái là hợp lệ nếu giá trị của nó là <= giá trị của chữ cái lớn nhất đã được sử dụng hoặc nó là chữ cái tiếp theo được sử dụng.

Bằng cách nào đó truy vấn cần phần LENGTH (s) <: n để chạy, tôi phải thiếu một cái gì đó trong cách truy vấn hoạt động.

CHỌN chính đảm nhiệm việc lọc ra các đầu vào không hợp lệ và các chuỗi ngắn hơn được xây dựng trước khi đạt được độ dài được nhắm mục tiêu.

Phiên bản 412 byte

WITH a AS(SELECT * FROM(SELECT d,b,ROW_NUMBER()OVER(PARTITION BY b ORDER BY d)l FROM(SELECT CHR(64+DECODE(MOD(LEVEL,:i),0,:i,MOD(LEVEL,:i)))d,CEIL(LEVEL/:i)b FROM DUAL CONNECT BY LEVEL<=:i*:n))WHERE l<=b),v(s,c,p)AS(SELECT d,1,l FROM a WHERE b=1 UNION ALL SELECT s||d,c+1,l FROM v,a WHERE c+1=b AND(l<=LENGTH(REGEXP_REPLACE(s,'([A-Z])\1+','\1'))OR l=p+1))SELECT s FROM v WHERE LENGTH(s)=:n AND :i<=:n ORDER BY 1;

Không thử truy vấn 412 byte với 26. Nó đặt cơ sở dữ liệu ở chế độ hạn chế, ít nhất là trên phiên bản xe của tôi đang chạy trong bộ chứa docker trên macbook. Tôi có thể thử siêu dữ liệu tại nơi làm việc, nhưng thật đáng buồn là tôi vẫn cần phải làm việc để kiếm sống.


0

Toán học, 136 byte

(For[j=2^#-1;t=#2,c=1;m=0;x=t;r=If[#>0,++m,c*=m;d=x~Mod~m+1;x=⌊x/m⌋;d]&/@j~IntegerDigits~2;;c<=t,t-=c;--j];FromCharacterCode[r+64])&

Để cho đầy đủ, đây là triển khai tham chiếu golf của tôi. Trái ngược với các câu trả lời hiện có, nó không chạy trong thời gian đa thức (nó theo cấp số nhân Nvới cơ sở 2) nhưng đáp ứng hạn chế về thời gian (trường hợp xấu nhất vẫn sẽ diễn ra trong vòng nửa giờ).

Ý tưởng là thế này:

  • Đối với mỗi sơ đồ vần, chúng ta có thể xác định các vị trí mà ký tự tối đa cho đến nay tăng:

    ABCDEFGHDIJDEKBBIJEIKHDFII
    ^^^^^^^^ ^^  ^
    

    Chúng ta có thể coi những dấu hiệu đó là một số nhị phân giúp dễ dàng lặp lại trên tất cả các cấu trúc như vậy. Chúng ta cần lặp lại từ 2 n-1 đến 2 n (hoặc ngược lại) là độ phức tạp thời gian theo cấp số nhân.

  • Đối với mỗi cấu trúc như vậy, thật dễ dàng để xác định có bao nhiêu chuỗi như vậy: chỉ có các khoảng trống giữa các dấu có thể được tự do lựa chọn và mức tối đa trước khoảng trống cho chúng ta biết có bao nhiêu ký tự khác nhau có giá trị ở mỗi vị trí. Đây là một sản phẩm đơn giản. Nếu con số này nhỏ hơn i, chúng tôi trừ đi i. Mặt khác, chúng tôi đã tìm thấy cấu trúc của sơ đồ vần được yêu cầu.
  • Để liệt kê các sơ đồ trong cấu trúc đã cho, chúng ta chỉ cần biểu diễn i(hoặc phần còn lại của nó) dưới dạng số cơ sở hỗn hợp, trong đó trọng số của các chữ số được xác định bởi số lượng ký tự được phép ở các vị trí còn lại.

Tôi tự hỏi nếu điều này sẽ cho phép một giải pháp ngắn hơn trong một số ngôn ngữ khác đã được gửi vì nó không yêu cầu bất kỳ sự phân biệt hoặc tiền xử lý.

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.