일정한 메모리를 사용하여 선형 시간에 문자열에서 모든 불균형 패런을 어떻게 찾을 수 있습니까?


11

인터뷰 중에 다음과 같은 문제가 발생했습니다.

다른 영숫자 문자와 함께 괄호 또는 괄호가 아닌 괄호가 아닌 괄호가 포함 된 문자열을 제공하고 일치하는 괄호가없는 모든 괄호를 식별합니다.

예를 들어, 문자열 ") (ab))"에서 인덱스 0과 5에는 일치하는 paren이없는 parens가 포함됩니다.

스택을 사용하여 스택에 parens를 추가하고 닫는 paren이 있고 스택의 맨 위에있을 때마다 스택에서 제거하면 문자열을 사용하여 O (n) 메모리를 사용하여 작동하는 O (n) 솔루션을 제시했습니다. 오프닝 패런.

그 후, 면접관은 일정한 메모리를 사용하여 선형 시간으로 문제를 해결할 수 있다고 지적했다 (입력에서 취한 것 외에 추가 메모리 사용이없는 것처럼).

나는 어떻게 그리고 그녀가 왼쪽에서 한 번 열리고 모든 열린 파렌을 식별하는 방법에 대해 말한 다음 오른쪽에서 두 번째로 모든 가까운 Parens를 식별하는 방법에 대해 물었다. 나는 정말로 이해하지 못했고 그것을 통해 그녀에게 손을 잡으라고 요청하고 싶지 않았습니다.

누구든지 그녀가 제안한 솔루션을 명확히 할 수 있습니까?


1
먼저 설명이 필요할 수 있습니다. "(()"의 첫 번째 파엔 또는 두 번째 파렌은 불균형으로 간주됩니까? "())"의 마지막 파엔 또는 두 번째에서 마지막 파렌은 불균형으로 간주됩니까? 아니면 최소한의 카디널리티를 가진 파렌 세트를 식별하는 것만으로도 충분한 양의 파 렌스를 제거 할 수 있습니까? 또는 다른 것? 아니면 답변이 정당한 사양을 제시 할 수 있도록 인터뷰의이 부분입니까?
John L.

나는 그것이 당신에게 중요하지 않다고 말할 것입니다. 나머지 균형을 유지하는 세트를 제거하십시오.
temporary_user_name

5
그런 다음 모두 제거하십시오; P
Veedrac

@Veedrac, 물론 (아시다시피) 포스터는 " 최소 세트 제거 .... "에서 "최소"라는 단어를 잊어 버렸습니다 .
LSpice

나는 "그것을 잊었다"는 것이 아니라, "모든 " 외에 균형을 잡기 위해 제거 할 수있는 단 하나의 세트 만 있기 때문에 나에게 중요한 사양처럼 보이지 않기 때문에 그것을 생략했다. 물론 운동의 목적을 어기는 것입니다.
temporary_user_name

답변:


17

이것은 이론적 인 컴퓨터 과학 연습이 아닌 프로그래밍 배경에서 비롯된 것이므로 , 인덱스를 문자열에 저장하는 데 영형(1) 메모리가 필요하다고 가정 합니다. 이론적 인 컴퓨터 과학에서 이것은 RAM 모델을 사용한다는 것을 의미합니다. Turing 기계를 사용하면이 작업을 수행 할 수 없으므로 길이 n 의 문자열에 색인을 저장 하려면 Θ(로그()) 메모리가 필요합니다 .

사용한 알고리즘의 기본 원칙을 유지할 수 있습니다. 메모리 최적화 기회를 놓쳤습니다.

스택에 parens을 추가하고 닫는 paren이 생길 때마다 스택에서 parens를 추가하고 스택에서 제거하면 문자열을 통과하고 스택 상단에 여는 paren이 포함됩니다.

이 스택에는 무엇이 포함되어 있습니까? 결코 포함 않을 것 ()(가) 때마다 때문에, (닫는 괄호 뒤에 여는 괄호)를 )표시하면 팝업 (대신을 밀어 ). 따라서 스택은 항상 )…)(…(괄호로 묶인 괄호와 여러 괄호로 묶습니다.

이것을 나타 내기 위해 스택이 필요하지 않습니다. 닫는 괄호 수와 여는 괄호 수를 기억하십시오.

이 두 카운터를 사용하여 문자열을 왼쪽에서 오른쪽으로 처리하는 경우 끝에있는 것은 일치하지 않는 닫는 괄호의 수와 일치하지 않는 여는 괄호의 수입니다.

Θ()

요약 : 문자열을 왼쪽에서 오른쪽으로 처리하십시오. 비교할 수없는 여는 괄호 카운터를 유지하십시오. 여는 괄호가 있으면 카운터를 늘리십시오. 닫는 괄호가 있고 카운터가 0이 아닌 경우 카운터를 줄이십시오. 닫는 괄호가 표시되고 카운터가 0이면 현재 색인을 일치하지 않는 닫는 괄호로 출력하십시오.

카운터의 최종 값은 일치하지 않는 여는 괄호의 수이지만 이로 인해 위치가 표시되지는 않습니다. 문제는 대칭입니다. 일치하지 않는 여는 괄호의 위치를 ​​나열하려면 반대 방향으로 알고리즘을 실행하십시오.

연습 1 : 공식 표기법 (수학, 의사 코드 또는 자주 사용하는 프로그래밍 언어)으로이를 작성하십시오.

연습 2 : 이것이 다르게 설명 된 Apass.Jack 과 동일한 알고리즘임을 확신하십시오 .


오, 아주 좋은 Gilles는 아주 잘 설명했습니다. 나는 지금 완벽하게 이해합니다. 내 질문 중 하나에 대한 답변을 얻은 지 꽤 몇 년이 지났습니다.
temporary_user_name

"끝에 일치하지 않는 괄호의 위치를보고하려면 각 괄호의 위치를 ​​기억해야합니다." 좀 빠지는. 선형 시간은 단일 패스를 의미하지 않습니다. 일치하지 않는면에서 괄호를 찾아서 표시하기 위해 두 번째 패스를 수행 할 수 있습니다.
Mooing Duck

마지막 단계에서는 역순으로 실행할 필요가 없으며 마지막 N "("을 불일치로 표시 할 수 있습니다.
Mooing Duck

1
@MooingDuck 작동하지 않습니다. 예 (().
orlp

이 답변이 정말 마음에 들지만 무언가가 계속 귀찮게합니다. "어떻게 든 나는 그 위치를 기억할 필요가있다. 그리고 내가 가진 문제는 메모리를 소비하지 않고 어떻게"현재 인덱스를 출력 하는가 "(또는 당신의 출력이 그런 식으로 소비되는 매우 구체적인 맥락이다) – 출력의 순서는 중요하지 않습니다.
Édouard

8

모든 영숫자를 무시할 수 있기 때문에 지금부터는 문자열에 괄호 만 포함되어 있다고 가정합니다. 질문에서와 같이 한 종류의 괄호 "()"만 있습니다.

균형 괄호를 더 이상 제거 할 수 없을 때까지 균형 괄호를 계속 제거하면 나머지 모든 괄호는 "))…) ((… (", 모든 불균형 괄호입니다. 그 전에 불균형 종료 괄호 만 있고 그 후에 불균형 여는 괄호 만 있습니다.

알고리즘은 다음과 같습니다. 간단히 말해서, 전환점을 먼저 계산합니다. 그런 다음 추가 닫는 괄호를 출력하여 문자열을 시작점에서 오른쪽으로 전환점까지 스캔합니다. 대칭 적으로 추가 오프닝 괄호를 출력하여 전환점까지 끝에서 왼쪽으로 스캔합니다.


str

초기화하십시오 turning_point=0, maximum_count=0, count=0. 각각 i에서 다음 0n-1수행하십시오.

  1. 인 경우 str[i] = ')'1에 1을 추가하십시오 count. 그렇지 않으면 1을 빼십시오.
  2. 만약 count > maximum_count설정 turning_point=i하고 maximum_count=count.

이제 turning_point전환점의 색인입니다.

리셋 maximum_count=0, count=0. 각각 i에서 다음 0turning_point수행하십시오.

  1. 인 경우 str[i] = ')'1에 1을 추가하십시오 count. 그렇지 않으면 1을 빼십시오.
  2. 인 경우을 count > maximum_count설정하십시오 maximum_count = count. i불균형 닫는 괄호의 색인으로 출력 합니다.

리셋 maximum_count=0, count=0. 각각의 경우 i에서 n-1turning_point+1아래로 다음을 수행하십시오.

  1. 인 경우 str[j] = '('1에 1을 추가하십시오 count. 그렇지 않으면 1을 빼십시오.
  2. 인 경우을 count > maximum_count설정하십시오 maximum_count = count. i불균형 여는 괄호의 색인으로 출력 합니다.

영형()영형(1)영형()


위의 알고리즘을 분석하면 실제로 전환점을 찾아 사용할 필요가 없다는 것을 알 수 있습니다. 모든 언밸런스 드 닫는 괄호가 흥미롭지 만 모든 언밸런스 드 여는 괄호가 무시되기 전에 발생한다는 훌륭한 관찰.

다음은 Python 코드입니다 .

여러 테스트 결과를 보려면 "실행"을 누르십시오.


연습 1. 위의 알고리즘이 나머지 카디널리티가 균형을 이루도록 카디널리티가 가장 적은 괄호 세트를 출력 함을 보여줍니다.

문제 1. 문자열에 "() []"와 같은 두 종류의 괄호가 포함 된 경우 알고리즘을 일반화 할 수 있습니까? 새로운 상황, 인터리빙 사례 "([)]"를 인식하고 처리하는 방법을 결정해야합니다.


Lol, 운동 1과 문제 1, 귀엽다. 설명한 알고리즘의 논리는 놀랍게도 시각화하기가 어렵습니다. 나는 그것을 얻기 위해 내일 이것을 코딩해야 할 것이다.
temporary_user_name

다소 명백하지만 가장 중요한 설명을 놓친 것 같습니다. 논리는 사실 매우 간단합니다. 먼저 각각의 추가 여는 괄호를 출력합니다. 전환점을 통과하면 각각의 추가 닫는 괄호가 출력됩니다. 끝난.
John L.

불균형 여는 괄호를 찾는 것이 잘못되었습니다. 즉, arr이 "())"이면 p는 2이고 p + 1은 arr 경계를 벗어납니다. 단지 아이디어-불균형 여는 괄호를 찾으려면 arr를 취소하고 알고리즘의 일부를 사용하여 불균형 한 닫는 괄호를 찾을 수 있습니다 (물론 역 적응 색인).
OzrenTkalcecKrznaric

+1

나는 이것을 이해하기 위해 조금 나왔지만, 나는 그것을 좋아한다. 그것은 꽤 영리하다. 그리고 내가 생각했던 모든 경우에 대해 작동한다
dquijada
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.