[프로그래머스] 완전탐색 | 모의고사 | Level 1 | 파이썬(Python)

letthem·2025년 1월 1일

CodingTest

목록 보기
1/24
post-thumbnail

솔직 발언: 코테 준비 진지하게 하는 건 처음이다.
알고리즘 스터디를 4-1 때 했었는데 너무너무 어려웠어서 내 힘으로 푼 문제가 거의 없다.
역시 이렇게 하니까 남는 게 없다.
근데 진짜 더이상은 미룰 수 없어서 새해기념 1일 1알고리즘 한 번 해볼까 한다. 시작 !
이번 코테 스터디는 최대한 나의 힘으로 제대로 해보겠다 ..!
처음하기 때문에 많이 미흡할 수 있다,, 동빈나 이코테 책 부록 파이썬 문법 부분(1학년 때 배워서 다 까먹었다ㅜㅜ)이랑 구글링과 지피티의 도움을 받으며 풀어보겠다

문제

문제 설명

수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.

1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...

1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.

제한 조건

시험은 최대 10,000 문제로 구성되어있습니다.
문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.

입출력 예

answersreturn
[1,2,3,4,5][1]
[1,3,2,4,2][1,2,3]

입출력 예 설명

입출력 예 #1

수포자 1은 모든 문제를 맞혔습니다.
수포자 2는 모든 문제를 틀렸습니다.
수포자 3은 모든 문제를 틀렸습니다.
따라서 가장 문제를 많이 맞힌 사람은 수포자 1입니다.

입출력 예 #2

모든 사람이 2문제씩을 맞췄습니다.


풀이

1번 수포자 배열 넣기

length = len(answers)

a = []
for i in range(length):
   a.append((i % 5) + 1)
   

이걸 리스트 컴프리헨션을 사용하면

a = [(i % 5) + 1 for i in range(len(answers))

이렇게 한 줄로 나타낼 수 있다!

2번 수포자 배열 넣기

b = []
for i in range(len(answer)):
    if i % 2 == 0:
        b.append(2)
    elif i % 8 == 1:
        b.append(1)
    elif i % 8 == 3:
        b.append(3)
    elif i % 8 == 5:
        b.append(4)
    elif i % 8 == 7:
        b.append(5)

그리구 일일이 다 해야하는건가 싶었는데
아예 패턴을 정의해서 직접 넣어줄 수가 있더라 !

b = []
pattern = [2, 1, 2, 3, 2, 4, 2, 5]  # 패턴 정의
length = len(answer)

for i in range(length):
    b.append(pattern[i % len(pattern)])  # 패턴 반복적으로 참조

이렇게 패턴을 정의해서 넣어줄 수 있다.

이걸 리스트 컴프리헨션을 사용하면

b_pattern = [2, 1, 2, 3, 2, 4, 2, 5]
b = [b_pattern[i % len(b_pattern)] for i in range(len(answers))]

이렇게 두 줄로 나타낼 수 있다!

3번 수포자 배열 넣기

c_pattern = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5] # 3번 수포자의 반복되는 패턴 정의
c = [c_pattern[i % len(c_pattern)] for i in range(length)]

3번도 2번과 동일하게 정의해주자

정답 개수 세기

count_a = 0

for i in range(length):
    if (answers[i] == a[i]):
        count_a += 1

print(count_a)

이런식으로 1번 수포자의 정답 개수를 셌는데
+= , -= 이런 연산자를 사용하려면 미리 0으로 초기화도 해줘야한다.

이것도 리스트 컴프리헨션을 사용하면

count_a = sum(1 for i in range(length) if answers[i] == a[i])

이렇게 sum 과 if 를 넣어 똑같이 쓸 수 있고, 리스트 컴프리헨션의 결과를 통해 값이 직접 할당되므로 count_a = 0 처럼 초기화해줄 필요도 없어진다 !

count_a = sum(1 for i in range(length) if answers[i] == a[i])
count_b = sum(1 for i in range(length) if answers[i] == b[i])
count_c = sum(1 for i in range(length) if answers[i] == c[i])

이것도 반복되니

counts = [
    sum(1 for i in range(length) if answers[i] == pattern[i])
    for pattern in [a, b, c]
]

count_a, count_b, count_c = counts

이렇게 합칠 수 있다.

가장 큰 count return / 동점자 오름차순 return

enumerate 를 사용하면 순회하면서 index를 만들어주고, 자동으로 오름차순으로 정렬된다.

max_value = max(counts)  # 가장 높은 점수

# 동점자 처리 (1번, 2번, 3번으로 오름차순 정렬)
answer = [i + 1 for i, count in enumerate(counts) if count == max_value]

max_value를 counts에서 찾고,
enumerate를 통해 counts를 순회하면서 count == max_value 조건을 만족하는 인덱스 i를 찾아,
i + 1을 answer 리스트에 추가한다!!

초기 풀이

def solution(answers):

    length = len(answers)
    
    # 1번 수포자
    a = [(i % 5) + 1 for i in range(length)]
    
    # 2번 수포자
    b_pattern = [2, 1, 2, 3, 2, 4, 2, 5] # 2번 수포자의 반복되는 패턴 정의
    b = [b_pattern[i % len(b_pattern)] for i in range(length)]
    
    # 3번 수포자
    c_pattern = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5] # 3번 수포자의 반복되는 패턴 정의
    c = [c_pattern[i % len(c_pattern)] for i in range(length)]
    
    # 맞춘 개수 count_a, count_b, count_c에 할당
    counts = [
        sum(1 for i in range(length) if answers[i] == person[i])
        for person in [a, b, c]
    ]
    count_a, count_b, count_c = counts
    
    # 가장 높은 점수
    max_value = max(counts)
    
    # 동점자 처리 (1, 2, 3으로 오름차순 정렬)
    answer = [i + 1 for i, count in enumerate(counts) if count == max_value]

    return answer

리스트 컴프리헨션으로 바꾸는 건 지피티가 알려줬는데 솔직히 내가 봐도 너무 겉멋만 든 코드 같다. 오히려 더 어렵게 보여서 가독성이 떨어지는 느낌(특히 counts 배열)? 그리고 배열 3개를 answer 길이만큼 다 만든 것도 너무 크기가 커질 수 있어서(공간 복잡도 ⬆) 바보같은 코드다

구글링과 상욱슨의 피드백으로 좀 더 다듬어보겠다.


최종 코드 😍

def solution(answers):
    answer = []
    
    length = len(answers)
    
    a = [1, 2, 3, 4, 5]
    b = [2, 1, 2, 3, 2, 4, 2, 5]
    c = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]
    
    # a, b, c의 득점
    scores = [0] * 3
    
    for i in range(length):
        if (a[i % 5]) == answers[i]:
            scores[0] += 1
        if (b[i % 8]) == answers[i]:
            scores[1] += 1
        if (c[i % 10]) == answers[i]:
            scores[2] += 1
    
    max_value = max(scores)
    
    for i in range(len(scores)):
        if scores[i] == max_value:
            answer.append(i + 1)
    
    return answer

a, b, c 리스트를 완전히 생성하지 않고, % 연산으로 패턴을 직접 순회해서 바로 scores를 계산하므로 메모리 사용량이 적고 속도도 더 빠르다!

for i in range(len(scores)):
    if scores[i] == max_value:
        answer.append(i + 1)

이건 앞서 사용했던 리스트 컴프리헨션으로

answer = [i + 1 for i in range(len(scores)) if scores[i] == max_value]

이렇게 나타낼 수 있다

0개의 댓글