포스트

TIL 2026-03-04

TIL 2026-03-04

3/4 - 알고리즘 강의 정리 & programmers 입문(1)

생성일: 2026년 3월 4일 오전 10:19

오늘 알고리즘 강의 정리

강의 범위

  • 이번 회차 목표: BFS/DFS까지 확실히 이해하고 구현
  • 이번 회차 제외: 백트래킹, 동적계획법, 다익스트라, 벨만-포드

느낀점

  • 라이브러리/메서드 활용 능력이 부족하다고 느꼈고, 이 부분을 중점 보완하기로 함
  • 문제 풀이 속도보다, 자료구조 선택과 표준 메서드 사용 숙련도를 먼저 높이기로 함

코딩테스트 문제 복기: 옹알이(aya, ye, woo, ma)

문제: 각 발음을 최대 1번씩만 사용해 단어를 만들 수 있을 때, 발음 가능한 단어 개수를 구하는 문제

image.png

부족했던 점

  • string 메서드(compare) 시그니처 이해 부족으로 초기 구현에서 호출 방식이 틀렸음
  • for/while의 위치 설계 미흡: match 실패 판정 위치가 잘못되어 조기 실패가 발생했음
  • range-based for 이해가 부족했음

###

정답 코드(기본형)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
int solution(vector<string> babbling) {
    int answer = 0;
    vector<string> token = {"aya", "ye", "woo", "ma"};

    // range-based for: babbling의 각 단어를 복사 없이(const reference) 순회
    for (const string& word : babbling) {
        vector<bool> used(4, false); // 각 발음은 최대 1번만 사용
        int pos = 0;                 // 현재 읽는 위치(왼쪽부터 소비)
        bool ok = true;

        // while 사용 이유: 단어 길이 끝까지 pos를 전진시키며 확인
        // (시간복잡도는 단어 길이 L에 비례, 전체 O(N * L * 4))
        while (pos < (int)word.size()) {
            bool match = false;

            for (int j = 0; j < (int)token.size(); j++) {
                int len = (int)token[j].size();

                // compare(pos, len, token[j]) == 0 :
                // word의 pos부터 len글자가 token[j]와 같으면 매칭
                if (!used[j] &&
                    pos + len <= (int)word.size() &&
                    word.compare(pos, len, token[j]) == 0) {
                    used[j] = true;
                    pos += len;      // 매칭된 길이만큼 이동
                    match = true;
                    break;
                }
            }

            // 토큰 전체를 다 확인한 뒤에도 매칭이 없을 때만 실패
            if (!match) {
                ok = false;
                break;
            }
        }

        // 카운트 증가 시점: '단어 하나' 검증이 끝난 뒤에만 증가
        if (ok && pos == (int)word.size()) {
            answer++;
        }
    }

    return answer;
}

복습 코드(유효 단어 목록 + count 출력)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
int solution(vector<string> babbling) {
    int answer = 0;
    int count = 0;
    vector<string> validWords;
    vector<string> token = {"aya", "ye", "woo", "ma"};

    for (const string& word: babbling) {
        vector<bool> used(4,false);
        int pos = 0;
        bool ok = true;

        while (pos < (int)word.size()) {
            bool match = false;
            for (int j = 0; j < (int)token.size(); j++) {
                int len = (int)token[j].size();
                if (!used[j] &&
                    pos + len <= (int)word.size() &&
                    word.compare(pos, len, token[j]) == 0) {
                    used[j] = true;
                    pos += len;
                    match = true;
                    break;
                }
            }
            if (!match) {
                ok = false;
                break;
            }
        }

        if (ok && pos == (int)word.size()) {
            answer++;
            count++;
            validWords.push_back(word);
        }
    }

    for (int i = 0; i < (int)validWords.size(); i++) {
        cout << validWords[i] << endl;
    }
    cout << count << endl;

    return answer;
}

int main() {
    vector<string> test = {"yewoo", "wooye", "mayeaya", "ayawooma", "woowoo", "aya"};
    cout << solution(test) << endl;
    return 0;
}

오늘 학습 포인트 요약

  • 핵심 로직: pos 포인터로 문자열을 끝까지 소비하면서 토큰 매칭
  • 중복 방지: used 배열로 각 발음 1회 제한 적용
  • 복잡도: O(N * L * 4) 수준으로 제한 내 충분히 안정적
  • compare/substring 계열 메서드 시그니처 10분 복습
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.