ช่วงเวลาท้องถิ่นของสตริง


20

ช่วงเวลาท้องถิ่น

ใช้เวลาไม่ว่างเปล่าสตริงs ระยะเวลาในท้องถิ่นของsที่ดัชนีฉันเป็นจำนวนเต็มบวกที่เล็กที่สุดnเช่นที่แต่ละ0 ≤ k <nเรามีs [ผม k +] = s [I-n + K]เมื่อใดก็ตามที่ทั้งสองฝ่ายจะมีการกำหนด อีกวิธีหนึ่งก็คือความยาวน้อยที่สุดของสตริงว่างWดังกล่าวว่าหากการ concatenation WWวางอยู่ติดกับsเพื่อให้สำเนาที่สองของWเริ่มต้นที่ดัชนีฉันของsจากนั้นทั้งสองสตริงเห็นด้วยก็ตามที่พวกเขาซ้อนทับกัน

เป็นตัวอย่างลองคำนวณช่วงเวลาท้องถิ่นของs = "abaabbab"ที่ดัชนี (อิง 0)

  • ลองn = 1 : จากนั้นs [2 + 0] ≠ s [2-1 + 0]ดังนั้นตัวเลือกนี้ไม่ถูกต้อง
  • ลองn = 2 : จากนั้นs [2 + 0] = s [2-2 + 0]แต่s [2 + 1] ≠ s [2-2 + 1]ดังนั้นนี่จึงไม่ถูกต้อง
  • ลองn = 3แล้วs [2 + 0-3]ไม่ได้ถูกกำหนดs [2 + 1] = s [2-3 + 1]และs [2 + 2] = s [2-3 + 2] ดังนั้นช่วงเวลาท้องถิ่นคือ 3

นี่คือการแสดงภาพของช่วงเวลาท้องถิ่นโดยใช้คำจำกัดความที่สองโดยเพิ่มเครื่องหมายอัฒภาคระหว่างสองสำเนาของwเพื่อความชัดเจน:

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

โปรดทราบว่าWไม่จำเป็นต้องเป็นย่อยของs สิ่งนี้เกิดขึ้นที่นี่ในกรณีดัชนี -4

งาน

ข้อมูลที่คุณป้อนเป็นสตริงที่ไม่ใช่อักขระที่มีอักขระ ASCII ตัวพิมพ์เล็ก มันสามารถนำมาเป็นรายการของตัวละครหากต้องการ ส่งออกของคุณจะเป็นรายการที่มีระยะเวลาในท้องถิ่นของsในแต่ละดัชนีของมัน ในตัวอย่างข้างต้นแสดงผลที่ถูกต้องจะเป็น[1,2,3,1,6,1,3,2]

จำนวนไบต์ต่ำสุดในแต่ละภาษาชนะ ใช้กฎมาตรฐานของ

กรณีทดสอบ

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 คุณสามารถหาWกับยาวเช่นเดียวกับs ในกรณีของqwertyuiop, Wqwertyuiopจะมีรุ่นที่หมุนของ ดูเพิ่มเติมตัวอย่างที่ดัชนี 4: Wไม่จำเป็นต้องเป็นย่อยของs
Zgarb

นั่นทำให้รู้สึก ฉันอ่านข้อความผิด ๆ
Arnauld

โบนัสจินตนาการสำหรับการแก้ปัญหาเวลาเชิงเส้น! (บุคคลอื่นอาจเสนอความโปรดปรานที่แท้จริงดังนั้นลองต่อไป)
user202729

ความท้าทายที่ประณีตมาก ๆ แต่ฉันสงสัยว่ามันจะเหมาะสมกว่าหรือไม่ที่จะกำหนดช่วงเวลาท้องถิ่นของแต่ละตำแหน่งระหว่างตัวละครสองตัว (เช่นที่ใดก็ตามที่;อยู่ในตัวอย่างของคุณ) นั่นจะกำจัดผู้นำอันดับ 1
มาร์ตินเอนเดอร์

@MartinEnder นั่นจะเป็นแนวคิดที่สะอาดกว่า แต่นิยามนี้ทำให้การสร้างเอาต์พุตง่ายขึ้นโดยวนลูปผ่านสตริงและเอาต์พุตจะไม่ว่างเปล่า
Zgarb

คำตอบ:


4

เรติน่า , 89 86 ไบต์

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

ลองออนไลน์! แก้ไข: บันทึกแล้ว 3 ไบต์ด้วย @MartinEnder คำอธิบาย:

.
$`¶$<'¶

แยกอินพุตที่แต่ละอักขระสร้างคู่ของบรรทัดหนึ่งรายการสำหรับคำนำหน้าและอีกหนึ่งสำหรับคำต่อท้ายของคำนำหน้า

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

เรียกใช้สคริปต์ที่เหลือในแต่ละคู่ผลลัพธ์

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

ค้นหาการจับคู่ที่ทับซ้อนกันทั้งหมดและรายการผลลัพธ์ (ดูด้านล่าง)

G`.

ยกเลิกการจับคู่ที่ว่างเปล่า

%C`.

ใช้ความยาวของการแข่งขันแต่ละครั้ง

N`

เรียงลำดับตัวเลข

0G`

ใช้เวลาน้อยที่สุด

การจับคู่ทำงานโดยการแยกส่วนนำหน้าและคำต่อท้ายออกเป็นสามส่วน มีกรณีที่ถูกต้องสี่ข้อที่ควรพิจารณา:

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

ดังนั้น regex อนุญาตให้ A และ C จับคู่ในด้านเดียวในแต่ละครั้ง


$&$'เท่ากับและการคำนวณความยาวสายสั้นกับ$<' tio.run/##K0otycxLNPz/X49LJeHQNhUb9UPbuPQ14mr0tDUPbdPT1o/ …%C`.
Martin Ender

4

ชวา 8, 167 154 152 ไบต์

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 ไบต์ขอบคุณที่@ceilingcat

ลองออนไลน์

คำอธิบาย:

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 ไบต์

รับอินพุตเป็นอาร์เรย์ของอักขระ

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)

กรณีทดสอบ


ฉันไม่แน่ใจว่าได้รับอนุญาตให้ใช้ชุดอักขระได้หรือไม่คุณแน่ใจหรือไม่ว่าพวกเขาไม่ใช่แค่สายอักขระ 1 ตัว?
Erik the Outgolfer

@EriktheOutgolfer ไม่มีประเภทอักขระใน JS ดังนั้นใช่: โดยทางเทคนิคแล้วจะเป็นอาร์เรย์ของสตริง 1 อักขระ ความเข้าใจของฉันคือว่าถ้ามัน quacks เหมือนสตริงมันเป็นสตริง (นี่คือเมตาโพสต์เกี่ยวกับสิ่งนั้น แต่อาจมีความเกี่ยวข้องมากกว่า - หรือสิ่งที่ขัดแย้งกับสมมติฐานของฉัน)
Arnauld

1
หรือจะกล่าวอีกนัยหนึ่ง: นี่ใกล้เคียงที่สุดเท่าที่เราจะไปถึงรายชื่อตัวละครใน JS ซึ่ง OP อนุญาตอย่างชัดเจน
Arnauld

1

Ruby , 104 102 ไบต์

->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}}

ลองออนไลน์!

แลมบ์ดายอมรับสตริงและส่งคืนอาร์เรย์

-2 ไบต์: สลับจุดสิ้นสุดของช่วงของช่วงด้วยตัวกั้นดัชนี

Ungolfed:

->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 ไบต์

บันทึก 1 ไบต์ขอบคุณ @Shaggy

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

ทดสอบออนไลน์!

คำอธิบาย

¬Ë@¯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.

ความคิดแรกของฉันคือการเปรียบเทียบอักขระแต่ละตัวในสตริงย่อยด้านซ้ายกับอักขระที่สอดคล้องกันในสตริงย่อยด้านขวาเช่นเดียวกับในคำตอบของ JS แต่นั่นไม่ได้ผลเนื่องจากวิธีการของ Japtor ที่จะทำให้ตัวละครนั้นอยู่ในส่วนอื่น ๆ ของสตริงถ้าดัชนีมีค่าเป็นลบหรือมากเกินไป

แต่โซลูชันของฉันสร้าง regex จากสตริงย่อยที่สองและทดสอบบนสตริงย่อยแรก ลองทำรายการที่ 5 ในกรณีทดสอบabaabbabเป็นตัวอย่าง:

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..$/

เคล็ดลับหลักคือ^สามารถจับคู่อนันต์จนกว่าจะจับคู่ตัวละครที่แท้จริง สิ่งนี้ช่วยให้เราสามารถละเว้นอักขระจำนวนใด ๆ ตั้งแต่เริ่มต้นของ regex ในขณะที่ตรวจสอบให้แน่ใจว่าส่วนที่เหลือทั้งหมดถูกจับคู่อย่างต่อเนื่องโดยจบที่ส่วนท้ายของสตริงทดสอบ

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


32 ไบต์
Shaggy

@Shaggy ขอบคุณเซมิโคลอนนั้นกำลังดักฟังฉัน: P
ETHproductions

1

C (gcc) , 143 142 140 139 128 126 123 ไบต์

  • บันทึกเป็นไบต์ แข็งแรงเล่นกอล์ฟไป!b&&printfb||printf
  • ที่บันทึกไว้สองไบต์ต้องขอบคุณเควิน Cruijssen ลบforวงเล็บของลูปร่างกายโดยการเล่นกลprintfตำแหน่ง
  • บันทึกเป็นไบต์ แข็งแรงเล่นกอล์ฟไปb+=S[i+k]!=S[i-n+k]b|=S[i+k]-S[i-n+k]
  • ไบต์สิบเอ็ดที่บันทึกไว้ ลบความต้องการl=strlen(S)โดยการปรับเงื่อนไขทั้งการจัดการสตริงให้หยุดเมื่อถึงจุดสิ้นสุดของสตริง (ไบต์ว่าง'\0')
  • บันทึกสองไบต์ แข็งแรงเล่นกอล์ฟไปi-n+k>~0i-n>~k
  • ที่บันทึกไว้สามไบต์ขอบคุณที่ceilingcat ; เทียบเท่ากับb||printf("|"),n++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];}

ลองออนไลน์!


คุณสามารถบันทึก 2 ไบต์โดยการลบวงเล็บและใส่b||printf("%d,",n)ใน for-loop: 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 bytes
Kevin Cruijssen

@KevinCruijssen ขอบคุณ
Jonathan Frech

@ceilingcat ขอบคุณ; ความเท่าเทียมที่เรียบร้อย
Jonathan Frech

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.