Kiểm tra nếu có một chuỗi con đẳng cấu


12

Câu hỏi này là một phần mở rộng của Kiểm tra nếu các từ là đẳng cấu và sao chép phần đầu tiên của câu hỏi để đưa ra định nghĩa về một đẳng cấu.

Hai từ là đẳng cấu nếu chúng có cùng kiểu lặp lại chữ cái. Ví dụ, cả hai ESTATEDUELEDcó mẫuabcdca

ESTATE
DUELED

abcdca

bởi vì chữ 1 và 6 giống nhau, chữ 3 và 5 giống nhau và không có gì khác. Điều này cũng có nghĩa là các từ có liên quan bởi một mật mã thay thế, ở đây với sự phù hợp E <-> D, S <-> U, T <-> E, A <-> L.

Cho hai chuỗi X và Y, với X không dài hơn Y, nhiệm vụ là xác định xem có chuỗi con nào của Y là một đẳng cấu với X.

Dữ liệu vào: Hai chuỗi ký tự không trống từ a..zA..Z mà một chuỗi trên mỗi dòng. Điều này sẽ đến từ đầu vào tiêu chuẩn.

Đầu ra Một chuỗi con của chuỗi thứ hai là một đẳng cấu với chuỗi thứ nhất, nếu một thứ như vậy tồn tại. Nếu không thì đầu ra "Không!".

Quy tắc Mã của bạn phải chạy trong thời gian tuyến tính trong tổng chiều dài của đầu vào.

Điểm Điểm của bạn là số byte trong mã của bạn. Ít byte nhất sẽ thắng.


Ví dụ đầu vào và đầu ra

adca
ddaddabdaabbcc

dabd

tiền boa

Có ít nhất người ta không phức tạp, thực tế nhanh và giải pháp thời gian tuyến tính cho vấn đề này.


@AlexA. Tôi nghĩ rằng ai đó đã nói với tôi rằng nếu bạn hạn chế thời gian chạy / độ phức tạp thì đó phải là thử thách mã. Tôi rất vui khi thay đổi nó nếu điều đó là sai tất nhiên.

7
Nếu thời gian chạy bị giới hạn bởi một quy tắc và không ảnh hưởng đến việc ghi bàn, thì môn đánh gôn có thể phù hợp hơn so với thử thách về mã.
Dennis

thời gian tuyến tính có nghĩa là nó cần phải là O (m + n) chứ không phải O (mxn) cũng không phải O (mx (nm)) trong đó m, n là độ dài của chuỗi thứ nhất và thứ 2?
một số người dùng

@someuser Có nghĩa là O (m + n).

1
@BetaDecay Xem "Cho hai chuỗi X và Y, với X không dài hơn Y, nhiệm vụ là xác định xem có chuỗi con nào của Y là một đẳng cấu với X không."

Câu trả lời:


8

Python 2, 338 326 323 321 310 306 297 293 290 289 280 279 266 264 259 237 230 229 226 223 222 220 219 217 ( 260 238 231 228 225 223 221 220 218 với 0 trạng thái thoát)

exec'''s=raw_input()
S=[M-s.rfind(c,0,M)for M,c in enumerate(s)]
k=0
j=x=%s
while k<=M+x:
 if S[k]>j<W[j]or S[k]==W[j]:
    k+=1;j+=1;T+=[j]
    if j-L>x:print s[k-j:k];z
 else:j=T[j]
'''*2%('-1;T=[0];W=S;L=M',0)
print'No!'

Thuật toán là một biến thể của KMP, sử dụng thử nghiệm dựa trên chỉ mục để khớp ký tự. Ý tưởng cơ bản là nếu chúng ta có một sự không phù hợp ở vị trí X[i]thì chúng ta có thể quay trở lại vị trí có thể tiếp theo cho một trận đấu theo hậu tố dài nhất của X[:i]nó là đẳng cấu với tiền tố X.

Làm việc từ trái sang phải, chúng tôi gán cho mỗi ký tự một chỉ số bằng khoảng cách đến lần xuất hiện gần đây nhất của ký tự đó hoặc nếu không có lần xuất hiện trước thì chúng tôi lấy độ dài của tiền tố chuỗi hiện tại. Ví dụ:

MISSISSIPPI
12313213913

Để kiểm tra xem hai ký tự có khớp nhau hay không, chúng tôi so sánh các chỉ số, điều chỉnh phù hợp cho các chỉ số lớn hơn độ dài của chuỗi (phụ) hiện tại.

Thuật toán KMP trở nên đơn giản hơn một chút vì chúng ta không thể có được sự không phù hợp trên ký tự đầu tiên.

Chương trình này xuất kết quả khớp đầu tiên nếu có. Tôi sử dụng một lỗi thời gian chạy để thoát trong trường hợp khớp, nhưng mã có thể dễ dàng sửa đổi để thoát sạch với chi phí của một số byte.

Lưu ý: Đối với các chỉ số điện toán, chúng ta có thể sử dụng str.rfind(trái ngược với cách tiếp cận trước đây của tôi bằng từ điển) và vẫn có độ phức tạp tuyến tính, giả sử rằngstr.rfind bắt đầu tìm kiếm từ cuối (có vẻ là lựa chọn thực hiện lành mạnh duy nhất) - cho mỗi ký tự trong bảng chữ cái , chúng ta không bao giờ phải đi qua cùng một phần của chuỗi hai lần, do đó, có một giới hạn trên của (kích thước của bảng chữ cái) * (kích thước của chuỗi) so sánh.

Vì mã đã bị xáo trộn khá nhiều trong quá trình chơi gôn, đây là một giải pháp sớm hơn (293 byte) dễ đọc hơn một chút:

e=lambda a:a>i<W[i]or a==W[i]
exec('s=raw_input();S=[];p={};M=i=0\nfor c in s:S+=[M-p.get(c,-1)];p[c]=M;M+=1\nW=S;L=M;'*2)[:-9]
T=[0]*L
k=1
while~k+L:
 if e(W[k]):i+=1;k+=1;T[k]=i
 else:i=T[i]
m=i=0
while m+i<M:
 if e(S[m+i]):
    if~-L==i:print s[m:m+L];z
    i+=1
 else:m+=i-T[i];i=T[i]
print'No!'

Các exét nghiệm chức năng tương đương của nhân vật. Câu execlệnh gán các chỉ số và thực hiện một số khởi tạo biến. Vòng lặp đầu tiên xử lý Xcác giá trị dự phòng và vòng lặp thứ hai thực hiện tìm kiếm chuỗi.

Cập nhật: Đây là phiên bản thoát hoàn toàn, với giá một byte:

r='No!'
exec'''s=raw_input()
S=[M-s.rfind(c,0,M)for M,c in enumerate(s)]
k=0
j=x=%s
while k<=M+x:
 if S[k]>j<W[j]or S[k]==W[j]:
    k+=1;j+=1;T+=[j]
    if j-L>x:r=k=s[k-j:k]
 else:j=T[j]
'''*2%('-1;T=[0];W=S;L=M',0)
print r

Tôi nghĩ bạn có thể tiết kiệm một byte bằng cách thực hiện python3. r=raw_inputso với r = inputtiết kiệm 4 byte và parens khi in chỉ tốn 3.
Maltysen

@Maltysen cảm ơn vì nhận xét. Tôi đã không xem xét Python 3 khi viết bài này, nhưng về chi phí và tiết kiệm, có thêm 2 byte vì bạn không thể trộn các khoảng trắng và tab để thụt lề trong Python 3.
Mitch Schwartz

@Maltysen chỉ để theo dõi, vấn đề bây giờ không còn là các tab mà là dấu ngoặc cho exec.
Mitch Schwartz

Đây là một câu trả lời thực sự tuyệt vời! Tôi mong muốn được nhìn thấy nó trong cjam ngay bây giờ :)

6

Python 3, 401 byte

import string,itertools
X=input()
Y=input()
x=len(X)
t=[-1]+[0]*~-x
j=2
c=0
while j<x:
 if X[j-1]==X[c]:c+=1;t[j]=c;j+=1
 elif c>0:c=t[c]
 else:t[j]=0;j+=1
s=string.ascii_letters
*b,=map(s.find,X)
for p in itertools.permutations(s):
 m=i=0
 while m+i<len(Y):
  if p[b[i]]==Y[m+i]:
   if~-x==i:print(Y[m:m+x]);exit()
   else:i+=1
  else:
   if-1<t[i]:m+=i-t[i];i=t[i]
   else:i=0;m+=1
else:print("No!")

Điều này vẫn chủ yếu là vô căn cứ, nhưng tôi nghĩ nó nên hoạt động. Thuật toán cốt lõi là KMP , cộng với một yếu tố bổ sung là yếu tố kích thước của bảng chữ cái (điều này là tốt, vì bảng chữ cái là không đổi). Nói cách khác, đây là / nên là một thuật toán tuyến tính hoàn toàn không thực tế.

Dưới đây là một vài chú thích để giúp phân tích:

# KMP failure table for the substring, O(n)
t=[-1]+[0]*~-x
j=2
c=0
while j<x:
 if X[j-1]==X[c]:c+=1;t[j]=c;j+=1
 elif c>0:c=t[c]
 else:t[j]=0;j+=1

# Convert each char to its index in a-zA-Z, O(alphabet * n)
s=string.ascii_letters
*b,=map(s.find,X)

# For every permutation of letters..., O(alphabet!)
for p in itertools.permutations(s):
 # Run KMP, O(n)
 m=i=0
 while m+i<len(Y):
  if p[b[i]]==Y[m+i]:
   if~-x==i:print(Y[m:m+x]);exit()
   else:i+=1
  else:
   if-1<t[i]:m+=i-t[i];i=t[i]
   else:i=0;m+=1
else:print("No!")

Để thử nghiệm, bạn có thể thay thế sbằng một bảng chữ cái nhỏ hơn string.ascii_letters.


2

APL (Dyalog) , 32 byte

Đây là hàm infix, lấy X làm đối số trái và Y làm đối số phải.

{(s,⊂'No!')⊃⍨(⍳⍨¨s←⍵,/⍨≢⍺)⍳⊂⍳⍨⍺}

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

{... } lambda anonymous nơi đại diện cho các đối số (X và Y)

⍳⍨⍺ɩ ndex selfie của X ( ɩ lần xuất hiện đầu tiên của các yếu tố của X trong X)

 kèm theo để chúng ta có thể tìm kiếm toàn bộ mô hình đó

(Giáo dục)⍳ ɩ Ndex xuất hiện đầu tiên về điều đó trong ...

  ≢⍺ kiểm đếm (chiều dài) của X

  ⍵,/⍨ tất cả các chuỗi con có kích thước đó của Y (giảm bớt sự kết hợp của những thứ đó, nhưng đó là không có)

  s← lưu trữ trong s(cho s ubstrings)

  ⍳⍨¨Self ndex selfie của mỗi người

 bây giờ chúng ta có chỉ mục của mẫu đầu tiên, hoặc 1 + số mẫu nếu không tìm thấy kết quả khớp

(Giáo dục)⊃⍨  sử dụng chỉ số đó để chọn từ

  ⊂'No!' chuỗi kèm theo (để nó hoạt động như một phần tử)

  s, chuẩn bị với s

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.