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(lg⁡n)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(log⁡n)
— 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, 모든 문자 확인을 위해 얼마나 자주는에서 찾을 수 있습니다 string1와 string2. 나는 문자가 다른 문자열보다 한 문자열에 더 자주 있으며, 순열이 아닙니다. 모든 문자의 빈도가 같으면 문자열은 서로의 순열입니다.

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

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(log⁡n)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.