문자열의 현지 기간


20

현지 기간

비어 있지 않은 문자열 s를 사용하십시오 . 인덱스 i 에서 의 s로컬주기 는 양의 정수 가 정의 될 때마다 각각의 0 ≤ k <n 에 대해 s [i + k] = s [i-n + k]를 갖도록 가장 작은 양의 정수 n 입니다. 대안으로, 비어 있지 않은 문자열 w 의 최소 ​​길이 는 연결 wws 옆에 배치 되어 w 의 두 번째 사본 이 s의 인덱스 i 에서 시작 하면 두 문자열이 겹치는 위치에 일치하게됩니다.

예를 들어, (0 기반) 인덱스 2에서 s = "abaabbab"의 로컬 기간을 계산해 봅시다 .

  • n = 1 : s [2 + 0] ≠ s [2-1 + 0]을 시도 하면이 선택이 올바르지 않습니다.
  • 시도 N = 2 : 다음 의 [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는 반드시의 하위 아닙니다 . 이것은 index-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 항상 s 와 같은 길이 의 w 를 찾을 수 있습니다 . 의 경우 , w는 의 회전 된 버전이 될 것입니다 . 인덱스 4의 예제도 참조하십시오. w 는 반드시 s 의 하위 문자열이 아닙니다 . qwertyuiopqwertyuiop
Zgarb

말이 되네요 나는 도전을 잘못 읽었다.
Arnauld

선형 시간 솔루션에 대한 가상 보너스! (다른 누군가가 실제 현상금을 제공 할 수 있으므로 계속 시도하십시오)
user202729

정말 깔끔한 도전이지만 두 문자 사이의 각 위치의 로컬 기간을 정의하는 것이 더 합리적인지 궁금합니다 (예 : 어디에서든지 ;예). 즉, 최고의 1을 없애 것이다
마틴 청산을

@MartinEnder 개념적으로 더 깔끔하지만이 정의를 사용하면 문자열을 반복하여 출력을 쉽게 만들 수 있으며 출력은 비워지지 않습니다.
Zgarb

답변:


4

망막 , 89 86 바이트

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

온라인으로 사용해보십시오! 편집 : @MartinEnder 덕분에 3 바이트가 절약되었습니다. 설명:

.
$`¶$<'¶

각 문자에서 입력을 분할하여 접두사와 접미사에 대한 한 쌍의 행을 만듭니다.

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

각 결과 쌍에서 나머지 스크립트를 실행하십시오.

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

따라서 정규 표현식은 A와 C 만 한 번에 한 쪽에서 만 일치하도록 허용합니다.


$&$'$<'계산 라인 길이가 더 짧습니다 %C`.. tio.run/##K0otycxLNPz/X49LJeHQNhUb9UPbuPQ14mr0tDUPbdPT1o/…
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;}

@ceilingcat 덕분에 -2 바이트 .

온라인으로 사용해보십시오.

설명:

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

자바 스크립트 (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 자 문자열이 아닙니까?
Outgolfer Erik

@EriktheOutgolfer JS에는 문자 유형이 없으므로 그렇습니다. 기술적으로 1 문자 문자열의 배열입니다. 내 이해는 그것이 문자열처럼 찌르면 문자열이라는 것입니다. (여기에 대한 메타 게시물이 있지만 더 관련성이 높은 게시물 이 있거나 실제로는 내 가정과 모순되는 게시물이 있을 수 있습니다.)
Arnauld

1
다른 말로하면 : 이것은 OP에서 명시 적으로 허용 한 JS 의 문자 목록에 도달 할 수있는 한 가깝습니다 .
Arnauld

1

루비 , 104102 바이트

->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 바이트 : 인덱스 바운드 가드가있는 스왑 범위 엔드 포인트

언 골프 드 :

->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 바이트

@Shaggy 덕분에 1 바이트 절약

¬Ë@¯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 응답 에서처럼 왼쪽 하위 문자열의 각 문자를 오른쪽 하위 문자열의 해당 문자와 ​​비교하는 것입니다. 그러나 인덱스가 음수이거나 너무 큰 경우 문자를 가져 오는 Japt의 방법은 문자열의 다른 끝으로 줄 바꿈되므로 작동하지 않습니다.

대신 내 솔루션은 두 번째 하위 문자열로 정규식을 작성하고 첫 번째 하위 문자열에서 테스트합니다. 테스트 사례에서 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..$/

주요 트릭은 ^실제 캐릭터가 일치 할 때까지 무한정 일치 할 수 있다는 것 입니다. 이를 통해 정규 표현식의 시작 부분에서 문자 수를 무시하고 나머지는 모두 테스트 문자열의 끝에서 연속적으로 일치하도록합니다.

잘 설명했는지 잘 모르겠으므로 설명하고 싶은 것이 있거나 설명해야 할 것이 있으면 알려 주시기 바랍니다.



@Shaggy 감사합니다, 그 세미콜론이 나를
괴롭 혔

1

C (GCC) , 143 (142) 140 139 128 126 123 바이트

  • 바이트를 저장했습니다. 에 골프 !b&&printf를 쳤다 b||printf.
  • Kevin Cruijssen 덕분에 2 바이트를 절약했습니다 . 배치 for를 저글링 하여 루프 본문 괄호를 제거했습니다 printf.
  • 바이트를 저장했습니다. 에 골프 b+=S[i+k]!=S[i-n+k]를 쳤다 b|=S[i+k]-S[i-n+k].
  • 11 바이트를 저장했습니다. l=strlen(S)문자열 끝에 도달 할 때 중단되도록 두 문자열 처리 루프를 조정 하여 필요를 제거했습니다 (null 바이트 '\0').
  • 2 바이트를 저장했습니다. 에 골프 i-n+k>~0를 쳤다 i-n>~k.
  • ceilingcat 덕분에 3 바이트를 절약했습니다 . 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];}

온라인으로 사용해보십시오!


대괄호를 제거하고 b||printf("%d,",n)for-loop에 넣으면 2 바이트를 절약 할 수 있습니다 . 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 바이트
Kevin Cruijssen

@KevinCruijssen 감사합니다.
Jonathan Frech

@ceilingcat 감사합니다; 깔끔한 동등성, 저것.
Jonathan Frech

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.