랩 어라운드 서브 시퀀스


11

소개

이 도전에서, 당신의 임무는 문자열의 일반화 된 하위 시퀀스를 찾는 것입니다. 서브 시퀀스가 ​​반드시 연속적인 것은 아니며, 스트링의 끝을지나 처음부터 다시 시작하여 스트링을 "감쌀"수도 있습니다. 그러나 랩 수를 최소화하고 싶을 것입니다.

더 공식적으로하자 uv두 문자열 및 수 k ≥ 0의 정수. 우리는 말 uA는 k-wrapping 서브v독특한 인덱스가있는 경우, 그러한가 , 대부분에서 인덱스의이 만족 . 이 수단 내부 찾을 수 있습니다 주위 가장에가는 길에 그 문자의 일부를 선택, 왼쪽에서 오른쪽으로 가고, 그리고 포장에 의해 시간 (동등 대부분에서 일 에 걸쳐 스윕 ). 랩 어라운드 후에도 문자를 두 번 이상 선택할 수 없으며 랩핑 하위 시퀀스는 모두 우리에게 익숙한 일반 하위 시퀀스입니다.i1, i2, ..., ilen(u)u == v[i1] v[i2] ... v[ilen(u)]kijij > ij+1uvkk+1v0

작업

입력 값은 비어 있지 않은 두 개의 영숫자 문자열 u이며 v출력값은-의 줄 바꿈 하위 시퀀스 k와 같은 가장 작은 정수 입니다 . 그러한 것이 존재 하지 않는다면 출력은이어야한다 .ukvk-1

입력 u := xyzyxzzxyx과를 고려하십시오 v := yxzzazzyxxxyz. 우리의 문자를 찾고 시작하는 경우 uv욕심 방식으로, 우리는 3 번 주위를 감싸합니다 :

 yxzzazzyxxxyz
>─x─────y────z┐
┌─────────────┘
└y───────x────┐
┌─────────────┘
└──zz─────x─y─┐
┌─────────────┘
└──────────x──>

따라서 올바른 출력은 최대 3입니다. 가장 왼쪽 문자 x를 한 번 선택한 다음 다시 쓸 수 없으므로 두 번째 스윕에서 무시되는 방식에 유의하십시오 . 그러나 랩 어라운드가 2 개인 짧은 방법이 있습니다.

 yxzzazzyxxxyz
>──────────xyz┐
┌─────────────┘
└yxzz────x────┐
┌─────────────┘
└───────y─x───>

하나의 랩 어라운드 (즉, 두 개의 스윕)로는 충분하지 않으므로 올바른 출력은 2입니다.

규칙 및 보너스

함수 또는 전체 프로그램을 작성할 수 있으며 필요한 경우 입력 순서를 변경할 수도 있습니다. 가장 낮은 바이트 수가 이기고 표준 허점이 허용되지 않습니다.

총 10 초 이내에 모든 테스트 사례를 계산할 때 보너스가 -10 % 입니다. 내 컴퓨터에서 불분명 한 사례를 테스트합니다. 파이썬에서 내 레퍼런스 구현은 약 0.6 초가 걸립니다. 1.86GHz 듀얼 코어 CPU가 장착 된 7 세짜리 랩톱이 있습니다.

테스트 사례

"me" "moe" -> 0
"meet" "metro" -> -1
"ababa" "abaab" -> 1
"abaab" "baabaa" -> 1
"1c1C1C2B" "1111CCCcB2" -> 3
"reverse" "reserved" -> 2
"abcdefg" "gfedcba" -> 6
"xyzyxzzxyx" "yxzzazzyxxxyz" -> 2
"aasdffdaasdf" "asdfddasdfsdaafsds" -> 2

1
이 예제에도 유효한 솔루션입니까? 욕심 많은 접근입니다.
orlp

@orlp 첫 번째 x는 세 개의 다른 스위프에서 사용 되므로 유효하지 않습니다 . 한 번만 사용할 수 있습니다.
Zgarb

아, 지금 봅니다.
orlp

답변:


4

Pyth, 34 바이트

Mh+Smssm>.ukC,dtdfqGsm@HkT.PUHlG_1

g두 개의 문자열을 매개 변수로 사용 하는 function을 정의합니다 . 온라인 사용해보기 : Pyth Compiler / Executor

이 코드는 매우 비효율적입니다. 시간과 메모리 복잡성이입니다 len(v)!/(len(v)-len(u))!. 10 초 안에 더 긴 테스트 사례를 해결할 수 없습니다. (메모리가 부족하기 때문에 충돌 가능성이 높습니다.)

M                                    define g(G, H): return _
                          .PUHlG        all permutations of [0, 1, ..., len(H)-1] of length len(G)
                 fqGsm@HkT              filter the permutations which form the string G
    mssm>.ukC,dtd                       compute the number of wraps for each of the remaining permutations
  +S                            _1      sort the numbers and append -1
 h                                      return the first element

4

하스켈, 160 * 0.9 = 144 바이트

a#(-1)=a
a#b=min a b
f y=w(y++" ")0$length y
w _ n _[]=n
w(c:d)n o g@(a:b)|n>o=(-1)|a==c=z#w y n z g|c==' '=w y(n+1)o g|1<2=w y n o g where z=w d n o b;y=d++[c]

모든 테스트 사례에 대한 타이밍 (참고 : 인수가 뒤집어 짐) :

*Main> map (uncurry f) [
             ("moe", "me"),
             ("metro", "meet"),
             ("abaab", "ababa"),
             ("baabaa", "abaab"),
             ("1111CCCcB2", "1c1C1C2B"),
             ("reserved", "reverse"),
             ("gfedcba", "abcdefg"),
             ("yxzzazzyxxxyz", "xyzyxzzxyx"),
             ("asdfddasdfsdaafsds", "aasdffdaasdf")]
[0,-1,1,1,3,2,6,2,2]
(0.08 secs, 25794240 bytes)

작동 방식 (짧은 버전) : 일치하는 문자를 사용하고 건너 뛰는 데 필요한 최소 무차별 대입 완료 (사이클 수 반환) 또는 최소값 이상으로 순환 (-1 반환)하면 검색을 중지합니다.

전체 프로그램에서 기능으로 전환했기 때문에 첫 번째 버전에 비해 많은 바이트를 절약했습니다.

몇 가지 의견과 적절한 간격으로 골프를 친 Haskell은 꽤 읽을 수 있습니다.

-- a minimum function that ignores a -1 in the right argument to prevent
-- "not solvable" cases in parts of the recursive search to dominate low numbers
-- of solvable parts. If the case isn't solvabale at all, both arguments are
-- -1 and are carried on.
a # (-1) = a
a # b    = min a b

-- the main function f calls the worker funktion w with arguments
-- * the string to search in (STSI), appended by a space to detect cycles
-- * the number of cycles so far
-- * the minimum of cycles needed so far, starting with the length of STSI
-- * the string to search for (STSF) (partial applied away and therefore invisible)
f y = w (y++" ") 0 (length y)

-- the worker function 
w _ n _ [] = n          -- base case: if STSF is empty the work is done and the 
                        -- number of cycles is returned

w (c:d) n o g@(a:b)     -- "c" is first char of STSI, "d" the rest
                        -- "n" number of cycles, "o" minimum of cycles so far
                        -- "g" is the whole STSF, "a" the 1st char, "b" the rest
  | n>o    = (-1)             -- if current cycle is more than a previous result,
                              -- indicate failure
  | a==c   = z # w y n z g    -- if there's a character match, take the min of
                              -- using it and skipping it
  | c==' ' = w y (n+1) o g    -- cycle detected, repeat and adjust n
  | 1<2    = w y n o g        -- otherwise try next char in STSI

  where                 -- just some golfing: short names for common subexpressions
  z = w d n o b;        -- number of cycles if a matching char is used
  y = d ++ [c]          -- rotated STSI

참조 : 이전 버전, 전체 프로그램, 187 바이트

main=interact$show.f.lines
a#(-1)=a
a#b=min a b
f[x,y]=w x(y++" ")0 0
w[]_ n _=n
w g@(a:b)(c:d)n m|a==c=w b d n 1#y|c==' '&&m==1=w g(d++" ")(n+1)0|c==' '=(-1)|1<2=y where y=w g(d++[c])n m

@ Zgarb : 내 솔루션을 재 작업했습니다. 이제 더 빠르고 짧습니다.
nimi

해석시 0.6 초, 컴파일시 0.01 초로 실행됩니다.
Zgarb

2

자바 스크립트 (ES6) 174 (193-10 %)

@nimi의 답변과 같은 재귀 검색은 랩을 최소화합니다. 솔루션 공간은 크지 만 (마지막 예제에서는 모두) 현재 검색된 최소 시간에서 검색을 줄이면 시간이 단축됩니다. 편집 1 누락 된 테스트 사례 추가, 비트 단축 편집 2 매개 변수 w를 전달할 필요가 없습니다.

K=(w,s,x)=>
  ~-(R=(r,l,p=0,q=1,z=w[p],i=0)=>
  {
    if(z&&!(q>x)){
      if(~(r+l).indexOf(z))
        for(t=l?R(l+r,'',p,q+1):x;x<t?0:x=t,i=~r.indexOf(z,-i);)
          t=R(r.slice(-i),l+r.slice(0,~i),p+1,q);
      q=x
    }
    return q
  })(s,'')

언 골프

K=(word, astring)=>
{
  var minWraps // undefined at first. All numeric comparison with undefined give false 
  var R=(right, left, pos, wraps)=>
  {
    var cur = word[pos]
    var i,t;
    if (! cur) // when all chars of word are managed
      return wraps;
    if (wraps > minWraps) // over the minimum wrap count already found, stop search
      return wraps; 
    if ( (right+left).indexOf(cur) < 0 ) // if the current char is not found in the remaining part of the string
      return minWraps; // return the current min, could still be undefined (that means 'no way')
    if ( left ) // if there is a left part, try a wrapping search with the current char
    {
      t = R(left+right, '', pos, wraps+1)
      if ( !(minWraps < t)) minWraps = t; // set current min if t is less than current min or current min is still undefined
    }
    // find all occurrences of current char in the remaining part
    // for each occurrence, start a recursive search for the next char
    for(i = 0; (i = right.indexOf(cur, i)) >= 0; i++)
    {
      var passed = right.slice(0,i) // the passed chars go in the left part
      var rest = right.slice(i+1) 
      t = R(rest, left+passed, pos+1, wraps) // try next char in the remaining part, no wrap
      if ( !(minWraps < t)) minWraps = t; // set current min if t is less than current min or current min is still undefined
    }
    return minWraps
  }
  var result = R(astring, '', 0, 1) // start with right=string and left empty
  return ~-result; // decrement. convert undefined to -1
}

Firefox / FireBug 콘솔에서 테스트

time=~new Date;
[['me','moe']
,['meet','metro']
,['ababa','abaab']
,['abaab','baabaa']
,['1c1C1C2B','1111CCCcB2']
,['reverse','reserved']
,['abcdefg','gfedcba']
,['xyzyxzzxyx','yxzzazzyxxxyz']
,['aasdffdaasdf','asdfddasdfsdaafsds']]
.forEach(s=>console.log(s,r=K(...s)))
time-=~new Date

출력 (마지막 라인은 실행 시간 (ms))

[ "me", "moe"] 0
[ "meet", "metro"] -1
[ "ababa", "abaab"] 1
[ "abaab", "baabaa"] 1
[ "1c1C1C2B", "1111CCCcB2"] 3
[ "역방향", "예약 됨"] 2
[ "abcdefg", "gfedcba"] 6
[ "xyzyxzzxyx", "yxzzazzyxxxyz"] 2
[ "aasdffdaasdf", "asdfddasdfsdaafsds"] 2
116


Firebug로 테스트되었으며 내 컴퓨터에서 175ms 동안 실행됩니다.
Zgarb

@Zgarb 그렇다면 개선의 여지가 있습니다. 느리고 짧게 만들려고합니다.
edc65
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.