HeoBrain AI · DEV · GROWTH

HEO BRAIN · DEV LAB

배운 것을 구조화하고,
실제로 작동하게 만듭니다.

AI, 코딩, 영어, 포트폴리오를 직접 공부하고 만들며 얻은 지식을 누구나 다시 써먹을 수 있게 정리합니다.

heobrain.workflow LIVE
01 collect(experience) 02 structure(knowledge) 03 ship(something useful)

TOPIC HUBS

무엇을 배우고 싶나요?

카테고리를 뒤지지 않아도 목표에 맞는 학습 경로와 글 모음으로 바로 이동합니다.

전체 글 보기

EMAIL NEWSLETTER

새 글을 이메일로 받아보세요

하루 동안 올라온 HeoBrain의 새 글을 매일 오후 8시에 한 통으로 보내드립니다.

인증 이메일의 링크를 눌러야 구독이 완료되며, 언제든 해지할 수 있습니다.

LATEST NOTES

최근에 정리한 글

모든 글 보기

《코딩 테스트 합격자 되기》_Array 정리

이 글의 목차 펼치기

코딩 테스트 합격자 되기 | 배열 학습 기록

오늘 읽은 배열 파트를 바탕으로, PDF에서 주고받은 문제 풀이와 문법 질문을 한 글로 다시 정리했다. 한 문제 안에서는 내가 작성한 풀이와 다른 풀이를 함께 비교한다.

1. 모의고사: 반복 패턴을 배열로 만들기

프로그래머스 모의고사

내 풀이

def solution(answers):
    patterns = [[1, 2, 3, 4, 5],
                [2, 1, 2, 3, 2, 4, 2, 5],
                [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]]
    scores = [0] * 3

    for i, answer in enumerate(answers):
        for j, pattern in enumerate(patterns):
            if answer == pattern[i % len(pattern)]:
                scores[j] += 1

    max_score = max(scores)
    result = []
    for i, score in enumerate(scores):
        if score == max_score:
            result.append(i + 1)
    return result

각 사람의 패턴을 2차원 리스트에 넣으면 사람 수가 늘어도 패턴만 추가하면 된다. i % len(pattern)은 패턴 끝에서 처음으로 돌아온다. enumerate가 꺼낸 answer를 쓰면 answers[i]를 다시 찾지 않아도 된다.

2. 행렬의 곱셈: 세 가지 풀이

프로그래머스 행렬의 곱셈

arr1의 한 행과 arr2의 한 열을 잡고, 같은 위치의 값끼리 곱해 더한다. arr1이 A x B, arr2가 B x C이면 결과는 A x C다.

내 풀이: 결과 배열을 먼저 만들기

def solution(arr1, arr2):
    r1, c1 = len(arr1), len(arr1[0])
    r2, c2 = len(arr2), len(arr2[0])
    result = [[0] * c2 for _ in range(r1)]

    for i in range(r1):
        for j in range(c2):
            for k in range(c1):
                result[i][j] += arr1[i][k] * arr2[k][j]
    return result

i는 arr1의 행, j는 arr2의 열, k는 곱할 위치다. [[0] * c2 for _ in range(r1)]는 각 행을 독립적으로 만든다. [[0] * c2] * r1은 행을 공유할 수 있어 사용하지 않는다.

다른 풀이: append()로 한 행씩 완성하기

def solution(arr1, arr2):
    answer = []
    for i in range(len(arr1)):
        row = []
        for j in range(len(arr2[0])):
            total = 0
            for k in range(len(arr1[0])):
                total += arr1[i][k] * arr2[k][j]
            row.append(total)
        answer.append(row)
    return answer

answer는 전체 결과, row는 결과 한 행, total은 결과 한 칸의 계산기다. 예전 코드의 productMatrix(A, B)도 같은 로직이지만, 현재 제출은 문제에서 준 solution 함수명을 쓴다.

짧은 풀이와 풀어 쓴 버전

def solution(arr1, arr2):
    return [[sum(a * b for a, b in zip(row, col))
             for col in zip(*arr2)]
            for row in arr1]
def solution(arr1, arr2):
    answer = []
    for row in arr1:
        new_row = []
        for col in zip(*arr2):
            temp_sum = 0
            for a, b in zip(row, col):
                temp_sum += a * b
            new_row.append(temp_sum)
        answer.append(new_row)
    return answer

zip(*arr2)는 arr2의 열을 꺼낸다. zip(row, col)은 행과 열의 같은 위치 값을 짝짓고, sum()은 곱한 결과를 더한다. 짧은 코드는 바로 아래의 세 겹 반복문을 압축한 것이다.

3. 실패율: count()와 빈도수 배열 비교

프로그래머스 실패율

처음 떠올리기 쉬운 방식

fail_count = stages.count(stage)

count()는 이해하기 쉽지만 스테이지마다 stages 전체를 다시 확인한다.

완성 풀이: 빈도수 배열

def solution(N, stages):
    challenger = [0] * (N + 2)

    for stage in stages:
        challenger[stage] += 1

    fails = {}
    total = len(stages)

    for stage in range(1, N + 1):
        if total == 0:
            fails[stage] = 0
        else:
            fails[stage] = challenger[stage] / total

        total -= challenger[stage]

    return sorted(
        fails,
        key=lambda stage: fails[stage],
        reverse=True
    )

N+1은 모든 스테이지를 통과한 사람의 위치다. 리스트 인덱스는 0부터 시작하므로 N+1을 안전하게 세려면 [0] * (N + 2)가 필요하다. 빈도수 배열은 참가자 목록을 한 번만 세므로 큰 입력에서 유리하다.

lambda를 정석 함수로 풀기

def get_fail_rate(stage):
    return fails[stage]

result = sorted(fails, key=get_fail_rate, reverse=True)

lambda stage: fails[stage]는 위 함수와 같다. 초안에서는 else 들여쓰기, total을 다음 스테이지 전에 빼는 위치, 빈 answer가 아니라 result를 반환하는 점을 수정했다.

4. 방문 길이: set과 함수 분리

프로그래머스 방문 길이

인라인 이동 풀이

def solution(dirs):
    x, y = 0, 0
    visited = set()
    moves = {
        "U": (0, 1),
        "D": (0, -1),
        "R": (1, 0),
        "L": (-1, 0)
    }

    for direction in dirs:
        dx, dy = moves[direction]
        nx, ny = x + dx, y + dy

        if -5 <= nx <= 5 and -5 <= ny <= 5:
            visited.add((x, y, nx, ny))
            visited.add((nx, ny, x, y))
            x, y = nx, ny

    return len(visited) // 2

기능을 나눈 풀이

def is_valid_move(nx, ny):
    return -5 <= nx <= 5 and -5 <= ny <= 5

def update_location(x, y, direction):
    moves = {
        "U": (0, 1),
        "D": (0, -1),
        "L": (-1, 0),
        "R": (1, 0)
    }
    dx, dy = moves[direction]
    return x + dx, y + dy

def solution(dirs):
    x, y = 0, 0
    visited = set()

    for direction in dirs:
        nx, ny = update_location(x, y, direction)

        if not is_valid_move(nx, ny):
            continue

        visited.add((x, y, nx, ny))
        visited.add((nx, ny, x, y))
        x, y = nx, ny

    return len(visited) // 2

이 문제는 방문한 점이 아니라 지나간 선을 센다. A에서 B로 간 길과 B에서 A로 돌아온 길은 같으므로 양방향 경로를 set에 넣고 2로 나눈다. add와 좌표 갱신은 반드시 for문 안에 있어야 한다.

문제 밖 질문: add(), append(), 문자열, 좌표계

리스트에는 append(), 문자열에는 + 또는 +=, 집합에는 add(), 딕셔너리에는 dict[key] = value를 쓴다. add()는 문자열 메서드가 아니다.

좌표를 0부터 10으로 옮기는 방식도 가능하지만, 시작점은 (5, 5), 범위는 0부터 10으로 끝까지 일관되어야 한다. 이 글은 원문과 같은 시작점 (0, 0), 범위 -5부터 5를 사용했다. 결과는 실수가 되는 /가 아니라 정수 나눗셈 //로 반환한다.

오늘의 배열 체크

한 문제를 풀 때는 정답 하나만 적지 않고, 내 풀이와 다른 풀이를 같은 자리에서 비교한다. 특히 짧은 풀이를 쓸 때는 반드시 같은 동작의 for문 버전도 함께 확인해 원리를 놓치지 않는다.

EMAIL NEWSLETTER

새 글을 이메일로 받아보세요

하루 동안 올라온 HeoBrain의 새 글을 매일 오후 8시에 한 통으로 보내드립니다.

인증 이메일의 링크를 눌러야 구독이 완료되며, 언제든 해지할 수 있습니다.

블로그 검색