Các giai đoạn địa phương của chuỗi


20

Thời kỳ địa phương

Lấy một chuỗi không trống s . Chu kỳ cục bộ của s tại chỉ số i là số nguyên dương n nhỏ nhất sao cho với mỗi 0 ≤ k <n , chúng ta có s [i + k] = s [i - n + k] mỗi khi cả hai bên được xác định. Ngoài ra, đó là độ dài tối thiểu của một chuỗi không trống w sao cho nếu nối ww được đặt bên cạnh s sao cho bản sao thứ hai của w bắt đầu tại chỉ số i của s , thì hai chuỗi đồng ý bất cứ nơi nào chúng trùng nhau.

Ví dụ: hãy tính khoảng thời gian cục bộ của s = "abaabbab" tại chỉ số 2 (dựa trên 0).

  • Hãy thử n = 1 : sau đó s [2 + 0] s [2-1 + 0] , vì vậy lựa chọn này không chính xác.
  • Hãy thử n = 2 : sau đó s [2 + 0] = s [2-2 + 0] nhưng s [2 + 1] ≠ s [2-2 + 1] , vì vậy điều này cũng không đúng.
  • Thử n = 3 : sau đó s [2 + 0-3] không được xác định, s [2 + 1] = s [2-3 + 1]s [2 + 2] = s [2-3 + 2] . Do đó, thời kỳ địa phương là 3.

Dưới đây là một hình ảnh của các thời kỳ địa phương bằng cách sử dụng định nghĩa thứ hai, với dấu chấm phẩy được thêm vào giữa hai bản sao của w cho rõ ràng:

index      a b a a b b a b      period
 0       a;a                     1
 1       b a;b a                 2
 2       a a b;a a b             3
 3             a;a               1
 4     b b a b a a;b b a b a a   6
 5                 b;b           1
 6               a b b;a b b     3
 7                   b a;b a     2

Lưu ý rằng w không nhất thiết là một chuỗi con của s . Điều này xảy ra ở đây trong trường hợp chỉ số-4.

Nhiệm vụ

Đầu vào của bạn là một chuỗi ký tự không trống của các ký tự ASCII viết thường. Nó có thể được lấy làm danh sách các ký tự nếu muốn. Đầu ra của bạn sẽ là danh sách chứa khoảng thời gian cục bộ của s tại mỗi chỉ số của nó. Trong ví dụ trên, đầu ra chính xác sẽ là [1,2,3,1,6,1,3,2] .

Số byte thấp nhất trong mỗi ngôn ngữ sẽ thắng. Luật tiêu chuẩn được áp dụng.

Các trường hợp thử nghiệm

a -> [1]
hi -> [1, 2]
www -> [1, 1, 1]
xcxccxc -> [1, 2, 2, 5, 1, 3, 2]
abcbacb -> [1, 4, 7, 7, 7, 3, 3]
nininini -> [1, 2, 2, 2, 2, 2, 2, 2]
abaabbab -> [1, 2, 3, 1, 6, 1, 3, 2]
woppwoppw -> [1, 4, 4, 1, 4, 4, 4, 1, 4]
qwertyuiop -> [1, 10, 10, 10, 10, 10, 10, 10, 10, 10]
deededeededede -> [1, 3, 1, 5, 2, 2, 5, 1, 12, 2, 2, 2, 2, 2]
abababcabababcababcabababcaba -> [1, 2, 2, 2, 2, 7, 7, 7, 7, 2, 2, 2, 19, 19, 5, 5, 2, 5, 5, 12, 12, 2, 2, 2, 7, 7, 5, 5, 2]

@Arnauld Bạn luôn có thể tìm thấy một w có cùng độ dài với s . Trong trường hợp qwertyuiop, w sẽ là phiên bản xoay của qwertyuiop. Xem thêm ví dụ ở chỉ số 4: w không nhất thiết là một chuỗi con của s .
Zgarb

Điều đó có ý nghĩa. Tôi đọc sai thử thách.
Arnauld

Phần thưởng tưởng tượng cho một giải pháp thời gian tuyến tính! (người khác có thể cung cấp tiền thưởng thực sự, vì vậy hãy tiếp tục thử)
user202729

Thử thách thực sự gọn gàng, nhưng tôi tự hỏi liệu sẽ có ý nghĩa hơn khi xác định khoảng thời gian cục bộ của từng vị trí giữa hai nhân vật (tức là bất cứ nơi nào ;trong ví dụ của bạn). Điều đó sẽ thoát khỏi vị trí dẫn đầu 1.
Martin Ender

@MartinEnder Điều đó sẽ sạch hơn về mặt khái niệm, nhưng định nghĩa này giúp sản xuất đầu ra dễ dàng hơn bằng cách lặp qua chuỗi và đầu ra sẽ không trống.
Zgarb

Câu trả lời:


4

Võng mạc , 89 86 byte

.
$`¶$<'¶
/(^|.+)¶.+/_(Lw$`^(.+)?(.*)(.+)?¶(?(1)|(.*))\2(?(3)$)
$2$3$4
G`.
%C`.
N`
0G`

Hãy thử trực tuyến! Chỉnh sửa: Đã lưu 3 byte nhờ @MartinEnder. Giải trình:

.
$`¶$<'¶

Tách đầu vào ở mỗi ký tự, tạo một cặp dòng, một cho tiền tố và một cho hậu tố của tiền tố.

/(^|.+)¶.+/_(

Chạy phần còn lại của tập lệnh trên mỗi cặp kết quả.

Lw$`^(.+)?(.*)(.+)?¶(?(1)|(.*))\2(?(3)$)
$2$3$4

Tìm tất cả các trận đấu chồng chéo và liệt kê kết quả. (Xem bên dưới.)

G`.

Hủy trận đấu trống.

%C`.

Lấy độ dài của mỗi trận đấu.

N`

Sắp xếp số lượng.

0G`

Lấy cái nhỏ nhất.

Sự phù hợp hoạt động bằng cách tách tiền tố và hậu tố thành ba phần. Có bốn trường hợp hợp lệ để xem xét:

AB|BC   B matches B to the left and B to the right
B|ABC   AB matches [A]B to the left and AB to the right
ABC|B   BC matches BC to the left and B[C] to the right
BC|AB   ABC matches [A]BC to the left and AB[C] to the right

Do đó, regex chỉ cho phép A và C khớp nhau ở một bên.


$&$'bằng $<'và độ dài dòng máy tính ngắn hơn với %C`.. tio.run/##K0otycxLNPz/X49LJeHQNhUb9UPbuPQ14mr0tDUPbdPT1o/...
Martin Ender

4

Java 8, 167 154 152 byte

s->{int l=s.length,r[]=new int[l],i=0,n,k;for(;i<l;r[i++]=n)n:for(n=0;;){for(k=++n;k-->0;)if(i+k<l&i+k>=n&&s[i+k]!=s[i-n+k])continue n;break;}return r;}

-2 byte nhờ @ceilingcat .

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

Giải trình:

s->{                          // Method with char-array parameter and int-array return-type
  int l=s.length,             //  Length of the input-array
      r[]=new int[l],         //  Result-array of the same size 
      i=0,n,k;                //  Integers `i`, `n`, and `k` as defined in the challenge
  for(;i<l;                   //  Loop `i` in the range [0, `l`):
      r[i++]=n)               //    After every iteration: Add `n` to the array
    n:for(n=0;;){             //   Inner loop `n` from 0 upwards indefinitely
      for(k=++n;k-->0;)       //    Inner loop `k` in the range [`n`, 0]:
                              //    (by first increasing `n` by 1 with `++n`)
        if(i+k<l&i+k>=n)      //     If `i+k` and `i-n+k` are both within bounds,
           &&s[i+k]!=s[i-n+k])//     and if `s[i+k]` is not equal to `s[i-n+k]`:
          continue n;         //      Continue loop `n`
                              //    If we haven't encountered the `continue n` in loop `k`:
      break;}                 //     Break loop `n`
  return r;}                  //  Return the result

1

JavaScript (ES6), 84 byte

Đưa đầu vào như một mảng các ký tự.

s=>s.map((_,i)=>s.some(_=>s.every(_=>k<j|!s[k]|s[k-j]==s[k++]|k-i>j,++j,k=i),j=0)*j)

Các trường hợp thử nghiệm


Tôi không chắc chắn nếu cho phép lấy một mảng các ký tự, bạn có chắc chúng không chỉ là chuỗi 1 ký tự?
Erik the Outgolfer 15/2/18

@EriktheOutgolfer Không có loại ký tự trong JS, vì vậy, đúng vậy: về mặt kỹ thuật đó là một chuỗi các chuỗi 1 ký tự. Sự hiểu biết của tôi là nếu nó quăng như một chuỗi, thì đó là một chuỗi. (Đây là một bài đăng meta về điều đó, nhưng một bài viết phù hợp hơn có thể tồn tại - hoặc một bài viết thực sự mâu thuẫn với giả định của tôi.)
Arnauld

1
Hay nói cách khác: nó gần giống như chúng ta có thể nhận được một danh sách các ký tự trong JS, được OP cho phép rõ ràng.
Arnauld

1

Ruby , 104 102 byte

->s{l=s.size-1
(0..l).map{|i|n=0
loop{n+=1
(n-i..l-i).all?{|k|k<0||k>=n||s[i+k]==s[i-n+k]}&&break}
n}}

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

Một lambda chấp nhận một chuỗi và trả về một mảng.

-2 byte: Hoán đổi điểm cuối phạm vi với bộ bảo vệ ràng buộc chỉ mục

Ung dung:

->s{
  l=s.size-1                # l is the maximum valid index into s
  (0..l).map{ |i|           # i is the current index
    n=0                     # n is the period being tested
    loop{                   # Repeat forever:
      n+=1                  # Increment n
      (n-i..l-i).all?{ |k|  # If for all k where i+k and i-n+k are valid indexes into s
        k<0 || k>=n ||      #   We need not consider k OR
          s[i+k]==s[i-n+k]  #   The characters at the relevant indexes match
      } && break            # Then stop repeating
    }
  n                         # Map this index i to the first valid n
  }
}

1

Japt , 33 32 byte

Đã lưu 1 byte nhờ @Shaggy

¬Ë@¯E f'$iUtED ú.D r."($&|^)"}aÄ

Kiểm tra nó trực tuyến!

Giải trình

¬Ë@¯E f'$iUtED ú.D r."($&|^)"}aÄ   Implicit: U = input string
¬Ë                                 Split the input into chars, and map each index E to
  @                          }aÄ     the smallest positive integer D where
   ¯E                                  the first E chars of U
      f                                matches the regex formed by
          UtED                         taking D chars of U from index E,
                ú.D                     padding to length D with periods,
                    r."($&|^)"          replacing each char C with "(C|^)",
        '$i                             and placing a '$' at the very end.

Suy nghĩ đầu tiên của tôi là chỉ so sánh từng ký tự trong chuỗi con bên trái với char tương ứng trong chuỗi con bên phải, như trong câu trả lời của JS. Tuy nhiên, điều đó sẽ không hiệu quả vì phương pháp của Japt để có được một ký tự chỉ kết thúc ở đầu kia của chuỗi nếu chỉ số âm hoặc quá lớn.

Thay vào đó, giải pháp của tôi xây dựng một regex ra khỏi chuỗi con thứ hai và kiểm tra nó trên chuỗi con đầu tiên. Hãy lấy mục thứ 5 trong trường hợp thử nghiệm abaabbablàm ví dụ:

abaabbab
    ^ split point -> abaa for testing regex, bbab for making regex

   slice  regex                              matches abaa
1. b      /(b|^)$/                           no
2. bb     /(b|^)(b|^)$/                      no
3. bba    /(b|^)(b|^)(a|^)$/                 no
4. bbab   /(b|^)(b|^)(a|^)(b|^)$/            no
5. bbab.  /(b|^)(b|^)(a|^)(b|^)(.|^)$/       no
6. bbab.. /(b|^)(b|^)(a|^)(b|^)(.|^)(.|^)$/  yes: /^^ab..$/

Thủ thuật chính là ^có thể khớp vô hạn, cho đến khi một nhân vật thực sự được khớp. Điều này cho phép chúng tôi bỏ qua bất kỳ số lượng ký tự nào từ đầu regex, trong khi đảm bảo rằng tất cả các ký tự còn lại được khớp liên tiếp, kết thúc ở cuối chuỗi thử nghiệm.

Tôi không chắc chắn tôi đã giải thích điều này rất tốt, vì vậy xin vui lòng cho tôi biết nếu có bất cứ điều gì bạn muốn làm rõ, hoặc bất cứ điều gì khác cần được giải thích.



@Shaggy Cảm ơn, dấu chấm phẩy đó đã làm phiền tôi: P
Sản phẩm điện tử

1

C (gcc) , 143 142 140 139 128 126 123 byte

  • Đã lưu một byte. Golfed !b&&printftới b||printf.
  • Lưu hai byte nhờ Kevin Cruijssen . Loại bỏ các fordấu ngoặc đơn thân vòng lặp bằng cách tung hứng printfvị trí.
  • Đã lưu một byte. Golfed b+=S[i+k]!=S[i-n+k]tới b|=S[i+k]-S[i-n+k].
  • Đã lưu mười một byte. Đã loại bỏ sự cần thiết của việc l=strlen(S)điều hòa cả hai vòng xử lý chuỗi để ngắt khi đến cuối chuỗi (một byte null '\0').
  • Lưu hai byte. Golfed i-n+k>~0tới i-n>~k.
  • Lưu ba byte nhờ trần nhà ; b||printf("|"),n++tương đương với n+=b||printf("|").
i,b,k,n;f(char*S){for(i=~0;S[++i];)for(b=n=1;b;n+=b||printf("%d,",n))for(b=k=0;k<n&&S[i+k];k++)b|=n-i>k?0:S[i+k]-S[i-n+k];}

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


Bạn có thể lưu 2 byte bằng cách xóa dấu ngoặc và đặt b||printf("%d,",n)vào vòng lặp for: i,b,k,n,l;f(char*S){for(l=strlen(S),i=-1;++i<l;)for(b=n=1;b;b||printf("%d,",n),n++)for(b=k=0;k<n;k++)i+k<l&i-n+k>=0&&(b+=S[i+k]!=S[i-n+k]);} 140 byte
Kevin Cruijssen

@KevinCruijssen Cảm ơn bạn.
Jonathan Frech

@ceilingcat Cảm ơn; tương đương gọn gàng, mà một.
Jonathan Frech

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.