O (n) 복잡성의 순서를 갖는 단어 빈도


11

Java 개발자 입장 인터뷰에서 다음과 같은 질문을 받았습니다.

두 가지 매개 변수를 취하는 함수를 작성하십시오.

  1. 텍스트 문서를 나타내는 String
  2. 반환 할 항목 수를 제공하는 정수

가장 자주 발생하는 단어 인 단어 빈도별로 정렬 된 문자열 목록을 반환하도록 함수를 구현하십시오. 솔루션은 시간에 실행되어야합니다. 여기서 은 문서의 문자 수입니다.O(n)n

다음은 내가 의사 코드로 대답 한 것입니다 .O 아니라 정렬 때문에 시간입니다. 시간 을 수행하는 방법을 알 수 없습니다 . O(n)O(nlogn)O(n)

wordFrequencyMap = new HashMap<String, Integer>();
words = inputString.split(' ');

for (String word : words) {
  count = wordFrequencyMap.get(word);
  count = (count == null) ? 1 : ++count;
  wordFrequencyMap.put(word, count);
}

return wordFrequencyMap.sortByValue.keys

누군가 알고 있거나 힌트를 줄 수 있습니까?


1
해시 테이블을 사용하십시오.
Yuval Filmus

해시 테이블을 사용해도 문제가 해결되지 않습니다. 또한 해시 테이블은 레거시 Java입니다.
user2712937

해시 테이블은 일반적으로 복잡성을 줄이는 트릭입니다. O(nlogn)O(n). 레거시 Java 인 경우에도 그 의미가 무엇이든 상관 없습니다. 이 특정 사례를 확인하지 않았으므로 귀하가 옳을 수도 있습니다.
Yuval Filmus 2016 년

@YuvalFilmus. 고맙지 만 해시 테이블은 이미 사용중인 해시 맵과 거의 동일합니다 (2 데이터 구조체의 주요 차이점은 동기화이며 여기에는 적용되지 않습니다). 내 log (n)은 해시 맵에서 값을 정렬하여 제공됩니다.
user2712937

3
그런데이 사이트는 코드가 아닌 개념과 알고리즘에 중점을 둡니다. 따라서 일반적으로 Java 코드를 제거하고 접근 방식에 대한 개념적 설명을 제공하도록 요청합니다 (필요한 경우 간결한 고급 의사 코드로). 또한이 사이트에서 어떤 데이터 구조와 알고리즘을 사용해야하는지 관련 질문이 있습니다. 특정 Java API는이 사이트에서 주제가 Hashtable맞지 않지만 ( StackOverflow에서 요청할 수 있음) 마찬가지로 레거시 Java 인지 여부 는이 사이트의 목적과 관련이 없습니다.
DW

답변:


10

분포 계산의 변형을 제안합니다.

  1. 텍스트를 읽고 각 노드에서이 노드가 나타내는 단어가 얼마나 자주 발생했는지 계산하여 각 노드에서 발견 된 모든 단어를 trie에 삽입하십시오 . 또한 가장 높은 단어 개수 say를 추적하십시오 maxWordCound. -O(n)
  2. size 배열을 초기화하십시오 maxWordCount. 입력 유형은 문자열 목록입니다. -O(n)카운트가 더 높을 수 없기 때문입니다.
  3. 트라이를 트래버스하고 각 노드에 대해 해당 문자열을 카운트로 표시된 배열 항목에 추가합니다. -O(n)문자열의 총 길이는 n.
  4. 내림차순으로 배열을 순회하고 원하는 수의 문자열을 출력합니다. -O(n)배열의 데이터 크기와 양에 모두 바인딩되어 있기 때문입니다.

첫 번째 단계에서 트라이를 다른 데이터 구조로 바꿀 수 있습니다.


+1이지만 확실하지 않습니다. 반환 할 단어 수는 문자 수 인 n으로 묶여 있기 때문에 O (n)이지만 질문이 묻는 것입니까? 또는 반환 된 단어 수와 무관 한 결과?
Nikos M.

@NikosM. 그것은 이다 ;n필요한 가정이 아닌 반환 된 단어 수에 대한 일반적인 최악의 상한입니다.
Raphael

@Raphael, 맞아 맞습니다. 인터뷰에서 질문을 받았기 때문에 이것에 대해 생각하고 있습니다. 질문에 가능한 트릭 ..
Nikos M.

공간 효율적인 선형 시간 알고리즘이 있는지 궁금합니다.
saadtaame

3
@saadtaame, yup, 흥미로운 질문입니다. 별도의 질문으로 별도로 게시 할 가치가있을 수 있습니다. 공간 효율성 만이 아닙니다. trie 솔루션은 포인터 집약적이므로 실제 시스템에서 메모리 계층 구조가 작동하는 방식으로 인해 실제로 느려질 수 있습니다. "효율성"은 최악의 실행 시간과 다릅니다. 깨끗한 것은 드문 일이 아닙니다O(nlgn) 포인터를 많이 사용하는 시간 알고리즘 O(n)시간 알고리즘 이므로이 질문은 이미 실제로 더 나은 선택이 될 수있는 몇 가지 잠재적 알고리즘을 배제하는 것으로 보입니다.
DW

3

발생 횟수 수집은 O (n)이므로 트릭은 실제로 최상위 k 발생 횟수 만 찾는 것입니다.

힙은 상위 k 값을 집계하는 일반적인 방법이지만 다른 방법을 사용할 수도 있습니다 ( https://en.wikipedia.org/wiki/Partial_sorting 참조 ).

k가 위의 두 번째 매개 변수이고 문제 설명에서 상수라고 가정합니다 (있는 것처럼 보입니다).

  1. 각 노드에서 발생 횟수를 가진 단어로 된 단어를 만드십시오.
  2. k 크기의 힙을 초기화하십시오.
  3. 최상위 k 힙에서 트라이 및 최소 프로브 / 삽입 각 (리프, 발생 횟수) 쌍을 순회하십시오.
  4. 상위 k 개의 잎과 수를 출력합니다 (각 잎을 단어로 다시 매핑하기 위해 부모 포인터가 필요하기 때문에 실제로는 일종의 고통입니다).

힙 크기는 상수이므로 힙 작업은 O (1)이므로 3 단계는 O (n)입니다.

더미를 작성하는 동안 힙을 동적으로 유지할 수도 있습니다.


2

알고리즘이 제 시간에 실행되지 않습니다 O(nlogn); 삽입Θ(n) 해시 테이블에있는 것들에 시간이 걸린다 Ω(n2) 이미 (최악의 경우).


다음은 잘못된 것입니다 . 나는 설명을 목적으로 한 동안 여기에 남겨두고 있습니다.

다음 알고리즘은 최악의 시간에 실행됩니다 O(n) (알파벳 가정 Σ 일정한 크기의), n 텍스트의 문자 수

  1. 텍스트 의 접미사 트리 ( 예 : Ukkonen 's algorithm)를 구성하십시오 .

    구성에서 아직이 작업을 수행하지 않은 경우 모든 (내부) 노드에 도달 가능한 잎 수를 추가하십시오.

  2. 뿌리에서 나무를 가로 질러 첫 번째 (흰색) 공간에서 모든 가지를 잘라냅니다.

  3. 나무를 가로 질러 잎 수에 따라 모든 노드의 자식 목록을 정렬하십시오.

  4. 나무의 수확량 (왼쪽에서 오른쪽으로 떠남)은 이제 빈도별로 정렬 된 모든 단어의 목록입니다.

런타임과 관련하여 :

  1. Ukkonen의 알고리즘 (향상된 형식)은 제 시간에 실행됩니다 O(n); 리프 수를 유지해도Θ알고리즘 비용.
  2. 텍스트에서 발생하는 모든 단어의 문자 당 하나의 노드를 순회해야합니다. 최대가 있기 때문에n 다른 단어 문자 쌍, 우리는 최대 방문 n 노드.
  3. 최대로 방문한다 n 노드 (2 참조) 시간을 보내십시오 O(|Σ|log|Σ|)=O(1) 노드 당.
  4. 수율을 얻을 수 있습니다. O(n)) 간단한 순회를 통해 O(n) (참조 2.).

다른 단어 수로 런타임을 매개 변수화하면보다 정확한 경계를 확보 할 수 있습니다. 몇 개가 없으면 2 이후에 나무가 작습니다.


알고리즘이 잘못되었습니다 (정렬되지 않음). 더 이상 선형 시간이 가능하지 않다고 확신합니다.
Raphael

1

해시 테이블 (예 :)을 사용하여 HashMap모든 단어와 해당 빈도를 수집하십시오. 그런 다음 카운팅 정렬 을 사용 하여 빈도가 감소하는 순서대로 단어를 정렬하십시오. 모든 주파수는 범위의 정수이므로1..n, 정렬 정렬 계산 O(n)시각. 총 예상 실행 시간은O(n)면접관이 귀하의 질문에서 빠진 것을 언급하지 않는 한 모든 실제 목적에 충분할 것입니다. 이것이 예상되는 실행 시간이 아니라 예상 되는 시간 임을 언급하십시오.최악의 .

이것은 교사가 알고리즘 클래스에서 찾고있는 대답이 아닐 수도 있습니다. O(n) 오히려 달리기 시간 O(n)최악의 경우 실행 시간 인터뷰 질문에서 추가 점수를 얻으려면 당연히이 시간이 예상되는 시간을 부담없이 언급 할 수 있지만O(n) 해시 테이블을보다 정교한 데이터 구조로 대체하여 최악의 실행 시간-이와 같은 상황에서 알고리즘 중에서 선택하는 방법에 대해 자세히 설명해 드리겠습니다.

또는 좀 더 안전하게 재생하려면 대답을하기 전에 먼저 "예상치의 차이에 대해 신경 쓰십니까? O(n) 실행 시간과 최악의 경우 O(n)러닝 타임? ". 그런 다음 그에 따라 답을 조정하십시오. 면접관이 실제로 어떻게 선택 하느냐고 물을 있도록 준비하십시오 . (그렇다면 점수를 매기십시오!


보관 Θ(n) 해시 테이블에있는 것들 Ω(n2)최악의 경우의 시간.
Raphael

나는 면접관을 위해 말할 수는 없지만 그들의 구어 짐을 같은 것에 대한 변명으로 사용하는 것을 주저합니다. 또한이 사이트는 과학에 관한 것입니다 (위에서 언급 한 것처럼) "손을 흔들며 더 빨리 지불하는 방법"프로그래밍 트릭은 아닙니다.
Raphael

이 이해가 명확하게 표현되어 있으면 괜찮습니다. 나는 암묵적인 "이해"가 잘못된 생각을 조장했기 때문에 혼란에 빠진 많은 질문들을 여기에서 보았다.
Raphael

0

해시 테이블 기반 솔루션

해시 테이블이 왜 복잡해 지는지 모르겠습니다. Ω(n2) 만약 n는 IS 문자 수 (없는 단어).

문서의 모든 문자를 반복하고 반복하면서 단어의 해시 코드를 계산하면 n문자. 즉, 글자가 나 오자마자 단어가 시작되므로 단어가 끝날 때까지 해시 계산을 시작하십시오 (구두에 대한 특별한 경우가 있지만 복잡성에는 영향을 미치지 않습니다). 모든 단어에 대해 해시가 계산되면 해시 테이블에 추가하십시오. 이것은 모든 단어를 두 번 거치지 않도록하는 것입니다. 즉, 먼저 문서를 반복하여 단어를 찾은 다음 해시 테이블에 삽입합니다.Ω(n).

해시 테이블의 충돌은 분명히 문제이며, 원래 해시 테이블의 크기와 해싱 알고리즘의 우수성에 따라 O(1) 삽입 및 카운트 유지를 위해 O(n)메모리를 희생하더라도 알고리즘에 적합합니다. 그러나 최악의 경우를 주장 할 수있는 방법을 여전히 이해할 수는 없습니다.O(n2) 만약 n 문자 수입니다.

해싱 알고리즘은 문자 수와 관련하여 시간이 선형이라고 가정합니다.

기수 정렬 기반 솔루션

또는 영어를 가정하면 단어의 길이가 잘 알려져 있기 때문에 대신 그리드를 만들고 기수 정렬을 적용합니다. O(kN) 어디 k 영어로 된 단어의 최대 길이 N총 단어 수입니다. 주어진n 문서의 문자 수 k 일정하며, 무증상으로 O(n).

이제 각 단어의 빈도를 세십시오. 단어가 정렬되었으므로 각 단어를 이전 단어와 비교하여 동일한 단어인지 다른 단어인지 확인합니다. 동일하면 단어를 제거하고 이전에 개수를 추가합니다. 다른 경우, 카운트 1을 만들고 계속 진행하십시오. 이것은 필요합니다2n 비교 n 문자 수이므로 O(n) 전체적으로 복잡합니다.

영어에서 가장 긴 몇 개의 단어는 엄청나게 길지만 단어 길이를 적당한 수 (예 : 30 이하)로 제한하고 오류가 발생할 수있는 단어를자를 수 있습니다.


(1) 대부분의 텍스트에서 단어의 최대 길이는 상수로 묶여 있기 때문에 단어 수는 Θ(n)게다가. (2) 해시 함수에 따라 단어를 읽는 동안 해시를 즉시 계산하지 못할 수 있습니다. (3) 최악의 경우, 모든 단어가 표에서 같은 위치로 해시되어 삽입 및 조회Θ(n).
FrankW

안녕 FrankW. (2) 즉시 계산할 수있는 기능 (즉, 롤링 해시)을 선택할 수 있다고 말하고 있습니다. 그렇지 않더라도 해싱이 선형 시간 인 한 전체 복잡도는 변경되지 않습니다. 읽기와 해싱은O(n+n)작업. (3) 물론 알고리즘의 선택에 달려 있습니다. 단어가 다른 경우 실질적으로 더 나은 알고리즘이 많이 있습니다. 같은 단어의 경우 단일 항목의 개수 만 늘리면됩니다. 비유로, 정렬 알고리즘을 선택해야 할 때 최악의 경우는O(n2)그러나 나는 일반적으로 더 나은 선택 :-)
Omer Iqbal

(3) 어떤 해시 기능을 선택하든 특정 기능이 저하되는 입력을 얻을 수 있습니다. 입력을 알고 나서 해시 함수를 선택하는 것은 일반적으로 옵션이 아닙니다. (그리고 아마도 당신이
말한 의견

해시 테이블은 왜 O(n2)최악의 경우? 원칙적으로 해시 테이블의 최악의 실행 시간이 매우 나쁘기 때문입니다. 실제로이 최악의 경우는 거의 발생하지 않는 것 같습니다 (특히 무작위 화 및 기타 기술을 사용하여 해시 함수를 올바르게 선택하는 경우). 그 이유를 정당화하기위한 이론을 입증 할 수도 있지만 이것이 점근 적 복잡성에 관한 질문 인 경우 , 그와 같은 실제적인 고려 사항은 논쟁의 여지없이 창 밖으로 나옵니다.
DW

일반적인 해시 테이블 삽입은 O(n2)충돌로 인해 항목을 다른 곳에 배치해야합니다. 여기서 중복을 삽입 할 필요는 없습니다. 1) 같은 단어가 반복됩니다 : 그런 다음 카운트를 올립니다.O(1)더하기 해싱 시간. 2) 다른 단어와 같은 해시 : 해시의 정도와 테이블 크기가 너무 작은 경우에 대한 질문입니다. 동의합니다Ω(1)하지만, 선택에 따라 나는 하나가 있었다 "고 말했다 접근 에 근접O(1) 삽입 및 카운트 유지 "를 참조하십시오. 우리는 어떤 테이블 크기와 함수를 사용하여 O(1).
Omer Iqbal 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.