상세 컨텐츠

본문 제목

리트코드 819. 가장 흔한 단어 (파이썬) - ✍️2차 할 차례

알고리즘/문자열 조작

by NayC 2021. 9. 8. 21:00

본문

728x90

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

 

Example 1:Input: paragraph = "Bob hit a ball, the hit BALL flew far after it was hit.", banned = ["hit"] Output: "ball" Explanation: "hit" occurs 3 times, but it is a banned word. "ball" occurs twice (and no other word does), so it is the most frequent non-banned word in the paragraph. Note that words in the paragraph are not case sensitive, that punctuation is ignored (even if adjacent to words, such as "ball,"), and that "hit" isn't the answer even though it occurs more because it is banned.

 

Example 2:

Input: paragraph = "a.", banned = [] Output: "a"


2차

 

 

 

1차

[접근 고민] 30분 하자. 10분 추가. 15분 추가

- paragraph에서 '단어'를 선별하기 위해 우선 split() 으로 공백 기준으로 단어들을 잘라내겠어

- paragraph 정리해주고. .lower() .replace(", , ." "") <- 이렇게 같이 해줄수 있는건가 싶지만

- for word in paragraph 로 

  잘라낸 단어들을 하나씩 다 읽어가는데, if word == banned 라면 paragraph.remove() ? 이런식으로 지우기? 

* 근데 banned 가 비어있는 경우도 있잖아? 음 비어있어서 같은게 없을테니 괜찮으려나 ㅎㅎㅎ 

 

문제 : 하나씩 읽는데, 그게 같은 단어인지 어떻게 알 것이며 + 어떻게 count 시켜줄 것인가

- 몇 번 occurs 되었는지 어떻게 알지? 

[bob, hit, a, ball, the, hit, ball, .....] 

word들을 하나씩 읽을건데... 

 

문제를 쪼개보자. 

그냥 bob, hit 이렇게 딱 2개만 비교한다고 생각해보자. 

이 2개 글자가 같은지 다른지 어떻게 판별함? 

-> 2개 str를 다른 변수로 저장해줘서

    첫번째 변수[0] == 두번째 변수[0] 이런식으로 비교해줄 것 같은데? 

 

* 다시 생각

* count를 세는 함수를 만든다고 생각해도 될 듯.banned랑 첫번째거가 같으면 다음번거를 꺼내주는거로

- 빈 리스트도 필요하겠고

 

1. list = paragraph.split() -> 리스트로 나오나?

2. for i in list:

i.replace(",", "")

i.lower()

list.append(i)

-> 데이터 클렌징의 필요성을 느꼈다 - 까지 만족. 오케이 

3. 이제 list 안에는 '단어' 하나하나가 들어있음.

// 여기서 count 어떻게 해줄지 생각하지 못했구나. 

   defaultdict(int기능이나, 풀어서 생각해보면 key에 단어를, value에 숫자를 넣어서 +1 하나씩 증가해주는 아이디어. 

-> 그리고 난 다음에 values가 가장 많은걸 출력해내는거지.

 

-> 2개씩 비교해야지 뭐.

3-1. 우선 빈 리스트는 2개 만들까.

한 개는 단어 같으면 넣어주는거. 다른 한 개는 다르면 가차없이 넣는거ㅎㅎㅎ

- 뭘 기준으로 비교하지

- banned랑 비교해서 같은거 넣어줄 수 있어. but and then?

3-2. banned같은 역할 (비교 기준) 하는 변수도 만들어서, for문 돌려서 직접 다 비교해야하나.

-> 아니야. 지금 list랑 역할이 같잖아.

그냥 '단어'라고 보면 되는데 '한 글자'씩 하려했던 것도 잘못된 흐름

 

count = 0 으로 밖에 둬서, 단어 비교 후 같을 때마다 += 하면 되는 것도 알겠어

-> 지금 내가 봉착한 문제 : 단어 비교를 어떻게 해줄 것이냐...


[코드 짜기]


[올바른 코드를 확인해보자]

 

import re
from collections import defaultdict
from operator import itemgetter

class Solution:
    def mostCommonWorld(self, paragraph:str, banned:list[str])->str:
        
        normalized_str = ''.join([c.lower() if c.isalnum() else ' ' for c in paragraph])
        words = normalized_str.split()

        word_count = defaultdict(int)
        banned_words = set(banned)

        for word in words:
            if word not in banned_words:
                word_count[word] +=1 

        return max(word_count.items(), key=itemgetter(1))[0]

cf) word_count.items() 하면 '쌍'이 출력됨. 

key=itemgetter(1)는 word_count의 (1)번째(여기서는 count가 되겠지) 기준으로 max인 거 뽑겠다는 것 

 

zsh: no matches found: [] 오류가 계속 나서 결과 확인은 못함 ㅠ

- 퇴근 후 저녁은 문제 풀며 문제해결력 증진하는 시간인데 이거로 더 이상 시간을 소비할 수 없다... 저 코드가 돌아가는거든 안돌아가는거든 논리 잡는게 더 큰 목표이기에 논리를 잡겠다.

 

cf) 다른 코드

def mostCommonWorld(self, paragraph:str, banned:list[str])->str:
        
        normalized_str = [word for word in re.sub(r'[^\w]', ' ', paragraph)
                            .lower().split()
                                if word not in banned]
        counts = collections.Counter(normalized_str)
        
        return counts.most_common(1)[0][0]

collections 모듈의 Counter 클래스 사용법

https://www.daleseo.com/python-collections-counter/


https://dojang.io/mod/page/view.php?id=2438 

 

https://wikidocs.net/69556

 

https://wikidocs.net/109327

 

setdefault를 사용하지 않고 호출과 동시에 미리 지정한 기본값이 할당되도록 선언할수는 없을까?
이럴때 defaultdict를 사용한다.
defaultdict를 활용해 다음과 같이 기본값을 ‘int’ 로 선언해주고,
기존에 없던 key를 호출하면 다음과 같이 해당 key가 0으로 자동 초기화된다.

https://itholic.github.io/python-defaultdict/

728x90
반응형

관련글 더보기