O (1) 추가 공간을 사용하여 두 문자열이 서로 순열인지 확인하는 방법은 무엇입니까?


13

두 개의 문자열이 주어지면 O (1) 공간을 사용하여 서로의 순열인지 어떻게 확인할 수 있습니까? 문자열을 수정하는 것은 어떤 식으로도 허용되지 않습니다.
참고 : 문자열 길이 및 알파벳 크기와 관련된 O (1) 공간.


3
어떻게 생각해? 당신은 무엇을 시도했으며 어디에서 갇히게 되었습니까? 문자열이 일정한 크기의 알파벳 위에 있습니까? 히스토그램 계산을 시도 했습니까?
Yuval Filmus 2016 년

@YuvalFilmus 그것은 문자열의 길이와 알파벳 크기 모두 O (1) 공간이어야합니다
Anonymous

이것은 분명히 불가능 해 보입니다. 모든 알고리즘은 하나의 문자열 또는 단일 문자에서 적어도 위치를 저장하기 위해 추가 공간이 필요합니다. 이들 중 어느 것도 O (1)가 아닙니다.
David Schwartz

@DavidSchwartz-어떻게? O (1)은 하나의 bute가 아닌 상수를 의미합니다. 문자열의 길이는 중요하지 않습니다. 문자열의 위치는 하나의 숫자입니다.
Davor

기계 모델에 따라 다르며 균일 한 모델에는 문제가 없습니다. 로그를 저장하는 로그 비용 모델에서, 인덱스는 O(log n)길이 n 또는 문자열 크기에 의해 일정하지 않은 길이 n의 문자열에 대한 것입니다. 문자열을 일시적으로 수정할 수있을 때 알파벳 크기는 선형이지만 로그 모델에서는 문자열 길이가 일정한 알파벳이 증가하는 솔루션이 있다고 생각합니다.
kap

답변:


7

순진한 접근 방식은 두 문자열의 히스토그램을 작성하고 동일한 지 여부를 확인하는 것입니다. 한 번에 계산할 수있는 데이터 구조 (알파벳 크기와 선형 인 크기)를 저장할 수 없으므로 가능한 각 심볼의 발생 횟수를 세어야합니다.

function count(letter, string)
    var count := 0
    foreach element in string
        if letter = element
            count++
    return count

function samePermutation(stringA, stringB)
    foreach s in alphabet
        if count(s, stringA) != count(s, stringB)
            return false
    return true

이것은 물론 카운트와 반복자 인덱스가 문자열의 길이에 의존하지 않고 일정한 크기의 정수라고 가정합니다.


최적화를 위해 하나의 배열로 이동하여 발생한 문자의 히스토그램 만 계산할 수 있습니다. 이러한 방식으로 복잡성은 알파벳 크기와 무관하게됩니다.
유발 Filmus

@YuvalFilmus 주석을 확장하려면 1) 문자열 길이가 같은지 확인하거나 2) 두 입력 문자열을 반복해야합니다. 하나의 문자가 다른 문자가 아닐 수 있으므로이 중 하나가 필요합니다. 옵션 1의 계산은 더 적어야합니다.
BurnsBA

@ YuvalFilmus 나는 이차 시간 복잡성을 의미하기 때문에 알파벳이 평균 문자열 크기보다 작을 것으로 기대합니다. 작은 문자열과 정렬 된 알파벳의 경우 내부 루프의 개수와 함께 다음으로 가장 작은 현재 심볼을 계산하여 복잡성으로 알파벳 루프의 몇 번의 반복을 건너 뛸 수 있습니다 O(n * min(n, |Σ|)). 흠, 이제 내가 생각하기에, 그것은 당신의 대답에서 "반복하도록 허용 된"해결책처럼 들리지 않습니까?
Bergi

count하지 않습니다 O(1)(즉 오버플로 수)
reinierpost

1
내가 말한 적이 @Eternalcode 그 count했다 int:-) 네,이 작품은,하지만 자바 않을 것이다 일어날 수없는 어쨌든
BERGI

12

배열을 로 표시하고 길이가 n 이라고 가정 합니다.A,Bn

먼저 각 배열의 값이 고유하다고 가정하십시오. 다음은 공간 을 사용하는 알고리즘입니다 .O(1)

  1. 두 배열의 최소값을 계산하고 동일한 지 확인하십시오.

  2. 두 배열의 두 번째 최소값을 계산하고 동일한 지 확인하십시오.

  3. 등등.

배열의 최소값을 계산하는 데 공간이 명확하게 사용 됩니다. 주어진 K 작은 요소 일, 우리는 찾을 수 있습니다 ( K + 1 ) 보다 큰 최소 값을 찾아 일 작은 요소 K 번째 작은 요소 (여기 우리가 모든 요소가 별개라는 사실을 사용).O(1)k(k+1)k

요소의 반복이 허용되면 다음과 같이 알고리즘을 수정합니다.

  1. 두 배열 의 최소값 을 계산하고, 각각 나타나는 횟수를 세고, m A , 1 = m B , 1 을 확인하고 카운트가 동일한 지 확인하십시오.mA,1,mB,1mA,1=mB,1

  2. 두 배열에서 각각 m A , 1 , m B , 1 보다 큰 최소값 계산하고 각각 나타나는 횟수를 세십시오. 그 확인 m의 , (2) =는 해요 B , 2 , 및 수는 동일 함.mA,2,mB,2mA,1,mB,1mA,2=mB,2

  3. 등등.


1
이 접근 방식 은 O ( 1 ) 공간 에서 최소 요소 를 찾고 배열에 대한 읽기 전용 액세스가 모든 요소를 ​​반복 하는 것이므로 입니까? O(n2)O(1)
ryan

4
알파벳 순서가 필요하지만 알고리즘을 요구하지 않도록 쉽게 변경할 수 있습니다. (가)의 경우 "중복 보유"에 그러나, 이것은 필요로 공간이 아닌 O ( 1 ) . 계산에는 공간이 필요합니다. O(lgn)O(1)
Derek Elkins가 SE

7
계산에는 (로그) 공간이 필요하지만 공간 사용에 대한 이러한 정의에 따라 배열을 반복 할 수도 있습니다. 따라서 공간 사용의 엄격한 의미 하에서 일정한 공간에서이를 수행 할 수있는 방법이 없습니다.
Daniel Jour

4
@DanielJour, 사용중인 비용 모델 에 따라 다릅니다 . 균일 한 비용으로 일정한 공간에서 가능합니다.
ryan

7
일정한 수의 비트 만 허용되는 경우, 일정한 크기의 알파벳 만 처리 할 수 ​​있습니다 (일반 언어 이론에 따름).
Yuval Filmus

2

일부 문자 c를 고유 한 소수 (a = 2, b = 3, c = 5 등)에 매핑하는 함수 f (c)를 정의하십시오.

set checksum = 1
set count = 0 <-- this is probably not even necessary, but it's another level of check
for character c in string 1
    checksum = checksum * f(c)
    count = count + 1
for character c in string 2
    checksum = checksum / f(c)
    count = count = 1

permutation = count == 0 and checksum == 1

소수 매핑 기능을 사용할 수 있다고 선언하는 것은 약간 손이 흔하며 공간을 유지하는 데 문제가 발생할 가능성이 높습니다 .O(1)


알파벳에 경계가 있으면 O ( 1 ) 공백을 사용해야 합니다. 그렇지 않으면 상수 공간이 아니라고 생각합니다. 또한 O ( 1 ) 공간 에서 계산 한 경우 현재 결과에 따라 매우 비효율적 입니다. 우선 순위 접근 방식의 경우 +1입니다. f(c)O(1)O(1)
ryan

게시 후 깨달은 또 다른 문제는 체크섬이 자체적으로 O (1) 공간 요구 사항을 위반할 수있는 정도로 큰 문자열의 경우 큰 숫자가된다는 것입니다. 이것은 하나의 문자열에서 부동 소수점을 사용하고 한 문자열에서 문자를 여러 번 나누고 다른 문자열로 나누면 체크섬 이 1에 가까워 야 합니다. 부동 소수점 오류가 문제가 되려면 문자열이 엄청나게 커야합니다 .
Alex Stasse

4
이러한 답변은 계산 모델을 조심해야하는 이유입니다. 알고리즘을 분석 할 때 사용하는 일반적인 모델 은 크기가 O ( log n ) 비트 인 기계 워드 단위로 메모리를 계산합니다 . 따라서 정수로 계산할 수 없습니다. 부동 소수점으로 전환하면 두 문자열이 서로 순열 된 경우에도 알고리즘이 실패 할 수 있으며 그렇지 않은 경우 반드시 정답을 제공하지는 않습니다. O(logn)
Yuval Filmus

4
일정한 공간을 사용하지 않습니다. 고정 알파벳의 경우에도 정수 체크섬의 크기 는 길이 n의 입력에 대해 비트가 됩니다. Θ(n)n
David Richerby

0

당신은 이것을 할 수 있습니다 O(nlogn). 두 문자열을 정렬하고 인덱스별로 인덱스를 비교하십시오. 그들이 어디에서나 다르면 서로의 순열이 아닙니다.

를 들어 O(n)솔루션, 해시를 사용할 수 있습니다. 해싱 함수는 작동 e하며 모든 문자의 ASCII 값입니다. 문자열의 두 해시가 다르면 서로의 순열이 아닙니다.

링크의 해싱 함수 :

잠재적 후보 중 하나가 이것 일 수 있습니다. 홀수 정수 R을 수정하십시오. 각 요소 e에 대해 계수를 해시 계산하려는 경우 (R + 2 * e). 그런 다음이 모든 요인의 곱을 계산하십시오. 마지막으로 해시를 얻기 위해 제품을 2로 나눕니다.

(R + 2e)의 요소 2는 모든 요소가 홀수임을 보장하므로 제품이 항상 0이되는 것을 피합니다. 끝에서 2로 나누면 제품이 항상 홀수하므로 나누기가 일정한 비트 만 제거하기 때문입니다. .

예를 들어, R = 1779033703을 선택합니다. 이것은 임의의 선택입니다. 어떤 실험을 수행하면 주어진 R이 좋은지 나쁜지를 보여야합니다. 값이 [1, 10, 3, 18]이라고 가정하십시오. 제품 (32 비트 정수를 사용하여 계산)은

(R + 2) * (R + 20) * (R + 6) * (R + 36) = 3376724311 따라서 해시는

3376724311/2 = 1688362155.

R의 값을 변경하여 이중 해싱 (또는 초과 사용)을 사용하면 이러한 값을 매우 높은 확률 로 순열로 식별 할 수 있습니다 .


1
문자열을 수정할 수 없으므로 문자열을 정렬 할 수 없습니다. 해싱에 관해서는 잘못된 답변을 줄 수있는 무작위 알고리즘입니다.
Yuval Filmus 2016 년

0

s와 t라는 두 개의 문자열이 있다고 가정 해 봅시다.

휴리스틱을 사용하여 동일하지 않은지 확인할 수 있습니다.

  1. s.length == t. 길이
  2. s의 문자 합 == t의 문자 합
  3. [2에서와 동일하지만 합계 대신 xor 사용]

그런 다음 문자열을 동일하게 증명하는 알고리즘을 쉽게 실행할 수 있습니다.

  1. 한 문자열을 다른 문자열과 동일하게 정렬하고 비교 (O (n ^ 2))
  2. 둘 다 정렬하고 비교 (O (2n log (n))
  3. 두 문자열에 같은 양이 있으면 s에서 각 문자를 확인하십시오 (O (n ^ 2))

물론 추가 공간을 사용할 수 없으면 빠르게 정렬 할 수 없습니다. 따라서 어떤 알고리즘을 선택하든 문제가되지 않습니다. 각 알고리즘은 O (1) 공간 만 있고 휴리스틱이 동일하지 않다는 것을 증명할 수없는 경우 O (n ^ 2) 시간에 실행됩니다.


3
" 어쨌든 문자열을 수정하는 것은 허용되지 않습니다. "
Bergi

0

전체 루틴에 대한 C 스타일 코드에서 :

for (int i = 0; i < n; i++) {
   int k = -1;
   next: for (int j = 0; j <= i; j++)
       if (A[j] == A[i]) {
          while (++k < n)
              if (B[k] == A[i])
                  continue next;
          return false; // note at this point j == i
       }
}
return true; 

또는 매우 상세한 의사 코드 (1 기반 인덱싱 사용)

// our loop invariant is that B contains a permutation of the letters
// in A[1]..A[i-1]
for i=1..n
   if !checkLetters(A, B, i)
      return false
return true

여기서 checkLetters (A, B, i) 함수는 A [1] .. A [i]에 A [i]의 M 개 사본이 있으면 B에 A [i]의 M 개 사본이 있는지 확인합니다.

checkLetters(A,B,i)
    k = 0 // scan index into B
    for j=1..i
      if A[j] = A[i]
         k = findNextValue(B, k+1, A[i])
         if k > n
            return false
    return true

findNextValue 함수는 인덱스에서 시작하는 값을 B에서 검색하고 찾은 인덱스 (또는 찾을 수없는 경우 n + 1)를 리턴합니다.

n2


C 코드를 의사 코드로 변환 할 수 있습니까? 이것은 프로그래밍 사이트가 아닙니다.
Yuval Filmus

이것은 Bergi의 답변의 또 다른 변형처럼 보입니다 (일부 중요하지 않은 차이점이 있음).
Yuval Filmus 2016 년

O(nm)O(n2)

0

O(n3n

루프를 string1하고 string2, 모든 문자 확인을 위해 얼마나 자주는에서 찾을 수 있습니다 string1string2. 나는 문자가 다른 문자열보다 한 문자열에 더 자주 있으며, 순열이 아닙니다. 모든 문자의 빈도가 같으면 문자열은 서로의 순열입니다.

이것을 정확하게 만드는 파이썬 조각이 있습니다.

s1="abcaba"
s2="aadbba"

def check_if_permutations(string1, string2):
  for string in [string1, string2]:
    # string references string1 
    #  string2, it is not a copy
    for char in string:
      count1=0
      for char1 in string1:
        if  char==char1:
          count1+=1
      count2=0
      for char2 in string2:
        if  char==char2:
          count2+=1
      if count1!=count2:
        print('unbalanced character',char)
        return()
  print ("permutations")
  return()

check_if_permutations(s1,s2)

stringstring1string2charchar1char2O(logn)count1count2string[string1, string2]

물론 카운트 변수가 필요하지 않지만 포인터를 사용할 수 있습니다.

s1="abcaba"
s2="aadbba"

def check_if_permutations(string1, string2):
  for string in [string1, string2]:
    # string references one of string1 
    # or string2, it is not a copy
    for char in string:
      # p1 and p2 should be views as pointers
      p1=0
      p2=0
      while (p1<len(string1)) and (p2<len(string2)):
        # p1>=len(string1): p1 points to beyond end of string
        while (p1<len(string1)) and (string1[p1]!=char) :
          p1+=1
        while(p2<len(string2)) and (string2[p2]!=char):
          p2+=1
        if (p1<len(string1)) != (p2<len(string2)):
          print('unbalanced character',char)
          return()
        p1+=1
        p2+=1
  print ("permutations")
  return()

check_if_permutations(s1,s2)

O(log(n))

n


아래의 Bergi 솔루션과 동일합니다.
Yuval Filmus 2016 년

@YuvalFilmus 아니요, 전체 알파벳을 반복하지 않으므로 런타임은 알파벳 크기에 의존하지 않습니다. 테스트해야 할 두 개의 문자열 만 사용합니다. 또한 두 번째 프로그램은 계산을 피합니다.
miracle173

@YuvalFilmus 나는 지금 당신과 다른 의견이 내가 프로그램에서 사용한 방식의 방향을 가리킨다는 것을 알았습니다.
miracle173
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.