알고리즘 문제 풀이

[알고리즘 문제 풀이] 가장 흔한 단어

sungw00 2022. 8. 19. 13:33
728x90

문제

금지된 단어를 제외한 가장 흔하게 등장하는 단어를 출력하라. 대소문자 구분을 하지 않으며, 구두점(마침표, 쉼표 등) 또한 무시한다.


예제1

입력

input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit."
banned = ["hit"]

출력

output: "ball"

풀이1 리스트 컴프리헨션과 defaultdict 모듈을 사용하기

입력값에는 대소문자가 섞여 있으며 쉼표 등 구두점이 존재한다. 따라서 데이터 클렌징을 이용해 입력값에 대한 전처리 작업이 필요하다.

좀 더 편리하게 처리하기 위해 정규식을 섞어 쓰면 다음과 같이 처리할 수 있다.

words = [word for word in re.sub(r'[^\w]', ' ', paragraph).lower().split() if word not in banned]

위 정규식에서 \w단어 문자를 뜻하며, ^not을 의미한다. 그대로 직역하면 단어 문자가 아닌 것을 그 뒤의 ' '에서 공백으로 치환하게 되므로 입력으로 들어온 문자열에서 단어 문자로 들어온 것이 아닌 나머지 문자를 모두 공백으로 치환하고, lower( )를 통해 소문자로 변환한 후 다시 split( )공백을 기준으로 분리해주게 된다. 이 과정에서 가장 우측에 있는 if문에서 banned 리스트에 속하지 않는 값을 word로 다시 옮겨주게 되니, 결국에는 단어 문자를 제외한 모든 불필요한 문자가 제거되어 words에는 단어만 담기게 된다. 그 이후에는 각 단어의 개수만 헤아려주면 된다.

 

counts = collections.defaultdict(int) # 기본으로 int 값을 자동으로 부여
    for word in words: # 위에서 가져온 단어들의 개수를 세어준다.
        counts[word] += 1 # 단어가 1번 등장할 때마다 1씩 증가

위 코드를 통해서 딕셔너리로 값을 생성하는데 기본으로 int 값을 자동으로 부여하게 하였으며, words의 단어 리스트를 가져와 word에 담아주고, counts 딕셔너리의 word(단어)에 해당하는 값에 +1을 해주면 각 단어의 갯수만큼 딕셔너리의 값이 계속해서 증가하게 된다.

 

return max(counts, key=counts.get)

이후에 counts에서 가장 많이 등장하는 단어를 리턴한다.

 

전체 코드는 다음과 같다.

# input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit."
# banned = ["hit"]
# output: "ball"
import collections
import re

def solution(paragraph: str, banned: list[str]) -> str:
    words = [word for word in re.sub(r'[^\w]', ' ', paragraph).lower().split() if word not in banned]
    # 첫번째 방법 -> defaultdict를 이용해 int 값 자동 부여하기
    counts = collections.defaultdict(int) # 기본으로 int 값을 자동으로 부여
    for word in words: # 위에서 가져온 단어들의 개수를 세어준다.
        counts[word] += 1 # 단어가 1번 등장할 때마다 1씩 증가
    return max(counts, key=counts.get)

banned = ["hit"]
print(solution(str(input("단어를 입력: ")), banned))

풀이2 Counter 객체와 most_common 함수를 사용한 풀이

먼저 데이터 클렌징 하는 부분은 위 방법과 동일하지만, 클렌징한 데이터에서 가장 많이 등장하는 단어를 추출하는 방법이 간소화된다.

most_common 함수의 인자로 가장 많이 등장하는 값을 앞에서부터 몇 개 출력할건지 전달하면 그 단어와 개수를 리턴받게 된다.

그 후 개수가 아닌 단어의 인덱스를 뽑아 리턴하면 깔끔하게 요구하는 출력대로 값을 리턴할 수 있다.

전체 코드는 다음과 같다.

# input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit."
# banned = ["hit"]
# output: "ball"
import collections
import re

def solution(paragraph: str, banned: list[str]) -> str:
    words = [word for word in re.sub(r'[^\w]', ' ', paragraph).lower().split() if word not in banned]
    # 두번째 방법 -> Counter 객체를 이용해 가장 흔하게 등장하는 단어를 most_common으로 추출
    counts = collections.Counter(words)
    return counts.most_common(1)[0][0]

banned = ["hit"]
print(solution(str(input("단어를 입력: ")), banned))

이처럼 가장 많이 등장하는 값(최빈값)을 구하는 문제에서는 Counter 객체를 이용하게 되면 비교적 간단히 구현할 수 있게 된다.


알게된 점

리스트 컴프리헨션을 통한 코드 간결화

collections 모듈의 Counter 객체와 most_common( ) 함수를 이용한 최빈값 출력

정규식을 통해 원하는 데이터를 구하기 위한 정규화 방법

 

공부할 것

리스트 컴프리헨션 구현하기

728x90