관리 메뉴

A seeker after truth

수업 퀴즈 문제 분석1 본문

Algorithm/문제풀이

수업 퀴즈 문제 분석1

dr.meteor 2020. 1. 2. 14:13

1. 문제 링크: http://mobilelab.khu.ac.kr/webpythonbbs/?board_name=PythonBBS&search_field=fn_title&search_text=Quiz&order_by=fn_pid&order_type=desc&vid=1027

 

 

* 내 문제 풀이 사고 과정

지금 이 문제 구조가

파일을 한 줄 씩 읽은 뒤,

한 줄을 split 하여 이름, 시간, 내용 정보 하나씩 얻을 수 있고

여기서 내용 정보는 필요 없다는 것을 알게 되었음.

 

한 줄을 읽었을 때,

1)파일의 끝일 경우, 파일에서의 작업은 종료하고 

2)이게 [로 시작하는 내용일 경우, 한 줄을 split 하여 이름, 시간, 내용 정보 하나씩 얻을 수 있고 여기서 내용 정보는 필요 없다는 것을 알게 되었음.

여기서 한 사람이 말한 발화의 “줄 수”를 카운트하는 딕셔너리를 만들어 여기에도 카운트 값을 추가한다.

3)[ 외 다른 것으로 시작할 때. - 말고 다른 걸로 시작할 때.
발화 줄수를 카운트 하는 일만 하면 된다.
근데 [로 시작하기 전까지 센 다음에, [가 나타나면 바로 없애야 한다는 점이 어려운 점… 결국 이름 만으로 구문하면 안되고, 뭘 구분자로 해야하나….  아 딕셔너리는 같은 키값에 대해선 중복되면 새로운 값으로 덮어쓴다는 성질을 이용하자… 하려 했더니 이게 최대값 보존이 안되네…아 돌게따

그러면 dict 내장 함수 중에 맥스가 있으면 최댓값을 보존하는 변수를 하나 만들어서 보관하자. 

아니면 이 부분은 튜플을 원소로 갖는 배열을 만들어서 보관하는 것도 굳? 메모리는 비효율적인데… 플밍은 편할듯

 

<해야할 일>

그니까 일단 [ 가 나타나기 전까지 한 줄 한 줄 읽고,

읽은 뒤에 lineCnt 는 무조건 증가시키고, // 까진 필수사항

처음일 경우: 이때 할건 이름 결정 밖에 없음
처음이 아닌 때부터: 그냥 카운트만
maxlineCnt
[ 만나기 바로 직전까지 카운트 올린 담에 비교하는게 맞는 같은데…? 전엔 굳이 

 


2. 내 풀이와 조교님 풀이 비교
- 내 풀이('가장 길게 말한 사람'을 찾는 알고리즘은 만들어내지 못했음):

filename = input("대화 파일 이름을 확장자 포함 입력하세요: ")
the_takative = dict()
takative_time = dict()
lengthy_one = dict()
most, time, line = None, None, None
# 한 발화에 가장 길게 말한 사람 찾기 위한 변수들
maxLineTalker = '' 
maxLineCnt = 1
lineCnt = 1 # 한 사람이 말한 횟수 저장 변수 

with open(filename,'r') as f:
    while True:
        line = f.readline()
        if line.startswith('['):
            most, time = line.split('] ')[0], line.split('] ')[1]
            # 많이 말한 사람
            if most not in the_takative: the_takative[most] = 1
            else: the_takative[most] += 1
            # 많이 말한 시간
            if time not in takative_time: takative_time[time] = 1
            else: takative_time[time] += 1
        elif line.startswith('-'): continue
        elif not line: break
        """
        else:
            while True:
                if line.startswith('[') != True: break
                if lineCnt == 1: maxLineTalker = most
                lineCnt += 1
                line = f.readline()
            if lineCnt > maxLineCnt:
                maxLineCnt = lineCnt
         """

            

    max_k, max_v = None, None
    for k,v in the_takative.items():
        if max_v==None or max_v < v:
            max_k = k
            max_v = v
    print("가장 많이 말한 사람: ", max_k[1:], ",   횟수: ", max_v)

    max_k, max_v = None, None
    for k,v in takative_time.items():
        if max_v==None or max_v < v:
            max_k = k
            max_v = v
    print("가장 많이 말한 시간: ", max_k[1:], ",   횟수: ", max_v)

    """
    max_k, max_v = None, None
    for k,v in lengthy_one.items():
        if max_v==None or max_v < v:
            max_k = k
            max_v = v
    print("가장 길게 말한 사람: ", "줄수: ")
    """

- 조교님 풀이:

http://mobilelab.khu.ac.kr/webpythonbbs/?board_name=PythonBBS&search_field=fn_title&search_text=Quiz&order_by=fn_pid&order_type=desc&vid=1033

 

 

3. 3번 문제(가장 길게 말한 사람 찾기)를 해결하지 못한 이유

파일의 한 줄을 읽을 때마다 1,2,3번 문제의 답을 구하기 위한 작업을 모두 하려고 했는데, 3번은 어떻게 할지 생각을 해내지 못했다. 1,2를 풀었을 때 3번 문제는 이해를 못해서 그런 것도 있었지만, 작업의 효율성을 위해 3번 작업을 하는 동안에는 1,2번을 위한 split 및 대입 작업을 일단 쉬어야 하며,  줄을 읽는 작업을 3번을 하는 동안에 자체적으로 계속 같이 해야 한다고 생각했기 때문. 매 줄 읽을 때마다 최댓값을 비교하는 작업이 비효율적이라 생각했다. 하지만 그렇게 생각하니 방법이 보이지 않았다.

 

 

4. 두 풀이 비교/분석(조교님 풀이가 내 풀이에 대한 피드백이라는 관점 하에)

1) 반복되는 부분은 함수로 빼서 처리

이 생각을 안한건 당연히 아니다. 이 작업이 코드 길이, 리팩토링, 가독성 등의 면에선 더 좋을지 모르나 함수 호출이라는 과정이 메모리를 먹는 작업이기 때문에, 이정도 수준의 알고리즘 문제에서는 그냥 일일이 작업해도 나쁘지 않겠다 생각했다. 어느 것이 더 나은지는 확실한 지식을 찾아보아야 알 수 있을 듯하다.

 

2) if/else 대신 try / except 구조의 활용

일단 파일을 열어놓고, 한줄씩 읽어들인다는 설정은 동일하다.

하지만 try/except 구조를 이런 식으로 활용하는 방법은 정말 생각 못했다...

imeRankDict[talkTime] += 1 이런 연산 했을 때, 그런 키값이 존재하지 않으면 에러가 날 텐데 그걸 except로서 처리하고 있다니!

특히 1차 try/except 부분! [로 시작하는 걸 try로, ----나 그외 문자로 시작하는걸 except로 다룬 것!

* 다만, if isFirst/else 부분 중 if isFirst 부분은 정말 존재 이유를 모르겠다. 왜냐면 isFirst의 초기값이 false인 이상 이 블록의 코드가 실행될 일은 없기 때문이다. 결국 else 아래 부분에 해당하는 maxcount VS linecount 비교 부분만 매번 실행되게 된다.

 

3) 3번 문제를 줄수 및 최대 줄수&발화자를 "저장하는 변수"를 만들어서 해결했다는 점

난 딕셔너리 +  딕셔너리에 중복 키값을 허용하지 않으며, 중복되면 새로운 값으로 덮어 씌워짐
혹은 튜플을 원소로 갖는 리스트 (튜플의 원소값은 변경이 불가능하지만, 그럼 같은 발화자에 대해 여러개의 튜플 데이터를 저장하고, 튜플 첫번째 자리에 해당하는게 사람의 이름이라면 두번째 자리에 해당하는 것을 줄 수로 둔 뒤 두번째 값들만 서로 비교하여 max를 반환하고 그의 인덱스를 통해 첫번째 원소인 발화자를 반환하려고 했던 아이디어)

혹은 [n][2]의 이차원 배열(튜플 리스트 아이디어와 같은 맥락)

을 사용하려 했으나, 이렇게 했을 때 밸류, 튜플/리스트의 두번째 위치 원소들을 꺼내와서 비교하기가 너무 번거로웠고

그게 아니더라도 어차피 readline을 startswith('[')하기 바로 직전에 딱 끊을 마땅할 방법을 고안하지 못해 시도할 수 있는 상황도 아니었다.

 

그런데 문제에서는

isFirst = False

maxLineTalker = ''

maxLineCnt = 0

lineCnt = 0

네 변수를 이용해서 해결을 했다. 값을 비교, 저장하기 위한 수단이 생각보다 단순했던 것.

 

4) strip 함수 처리

line에 대해 strip 처리를 하면 아무래도 깔끔하겠지. 특히 실무 상황이면 더욱.

 

 


아, 검색하다 우연히 알았는데 파이썬의 경우는 함수로 정의되지 않은 코드로 작동하는 프로그램보다 함수로 정의한 코드로 작동하는 프로그램이 속도가 빠르다고 한다. 자세한 내용은 아래 링크에서 확인할 수 있다.

https://wikidocs.net/22796

'Algorithm > 문제풀이' 카테고리의 다른 글

프로그래머스 정렬 문제풀이(1)  (0) 2020.01.24
문제5  (0) 2020.01.08
문제4  (0) 2020.01.08
파이썬 수업 문제 분석 3  (0) 2020.01.07
수업 퀴즈 문제 분석 2  (0) 2020.01.02