포스트

TIL 2026-04-08

TIL 2026-04-08

2026-04-08 TIL

목차


나누어 떨어지는 숫자 배열 (Lv.1)

🔗 https://school.programmers.co.kr/learn/courses/30/lessons/12910


문제 분석

문제 요약

vector<int> arr에서 int divisor나누어 떨어지는 원소만 골라 오름차순 정렬해서 반환.

나누어 떨어지는 원소가 없으면 [-1] 반환.

제한사항

  • arr의 길이: 1 이상 100 이하
  • arr의 원소: 100 이하의 자연수
  • divisor: 1 이상 10 이하의 자연수

입출력 예

arrdivisorreturn
[5, 9, 7, 10]5[5, 10]
[2, 36, 1, 3]1[1, 2, 3, 36]
[3, 2, 6]10[-1]

핵심 포인트

  • % 연산자로 나누어 떨어지는 원소 필터링
  • 결과가 없으면 [-1] 반환
  • 결과를 오름차순 정렬 후 반환 (sort() 필요)
  • 시간복잡도 O(n log n) — 정렬 포함

헤더 라이브러리

#include <vector>

1
2
3
4
vector<int> arr = {5, 9, 7, 10};
arr.size();              // 원소 개수
arr[i];                  // 인덱스 접근
arr.push_back(value);    // 원소 추가
  • 동적 배열 컨테이너
  • push_back() 으로 원소 추가

#include <algorithm>

1
2
3
4
5
sort(answer.begin(), answer.end());               // 오름차순 정렬 (기본)
sort(answer.begin(), answer.end(), greater<int>());  // 내림차순 정렬

copy_if(arr.begin(), arr.end(), back_inserter(answer),
        [divisor](int x){ return x % divisor == 0; });  // 조건 필터링
  • sort(first, last) — 범위를 오름차순으로 정렬
  • copy_if(first, last, dest, pred) — 조건(pred)을 만족하는 원소만 dest로 복사
  • back_inserter(v)v.push_back()을 호출하는 출력 이터레이터 반환
  • 람다 [divisor](int x){ return x % divisor == 0; } — divisor를 캡처해서 조건 판별

vector::empty()

1
if(answer.empty())    // size() == 0 과 동일, 더 간결
  • empty() — 벡터가 비어있으면 true 반환
  • size() == 0 보다 의미가 명확하고 간결

코드 풀이

풀이 1 — for 루프 + sort (작성한 코드)

시간복잡도: O(n + k log k) — 필터링 O(n) + 결과 정렬 O(k log k)

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
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

vector<int> solution(vector<int> arr, int divisor) {
    vector<int> answer;

    for (size_t i = 0; i < arr.size(); i++)
    {
        if(arr[i] % divisor == 0)
        {
            answer.push_back(arr[i]);
        }
    }

    if(answer.size() == 0)
    {
        answer.push_back(-1);
    }
    else
    {
        sort(answer.begin(), answer.end());
    }

    return answer;
}

-1을 넣은 경우엔 정렬하면 안 되므로 else 로 분기 처리

풀이 2 — copy_if + sort (STL 활용)

시간복잡도: O(n + k log k) — 동일, 코드 간결

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;

vector<int> solution(vector<int> arr, int divisor) {
    vector<int> answer;

    copy_if(arr.begin(), arr.end(), back_inserter(answer),
            [divisor](int x){ return x % divisor == 0; });

    if(answer.empty())
    {
        answer.push_back(-1);
    }
    else
    {
        sort(answer.begin(), answer.end());
    }

    return answer;
}

copy_if + 람다로 for 루프를 한 줄로 대체, empty()로 가독성 향상

시간복잡도 비교

풀이필터링정렬전체
풀이 1 (for 루프)O(n)O(k log k)O(n + k log k)
풀이 2 (copy_if)O(n)O(k log k)O(n + k log k)

k = 나누어 떨어지는 원소 수 (k ≤ n) / 두 풀이의 시간복잡도는 동일 — 풀이 2는 STL 스타일로 코드가 더 간결

복기

  • % 연산자로 나누어 떨어지는 조건 필터링
  • 결과 없을 때 [-1] 반환 처리 필수
  • -1 삽입 후 정렬하지 않도록 else 분기 필수
  • copy_if + back_inserter 로 for 루프 대체 가능
  • size() == 0 대신 empty() 사용이 더 관용적

백준 9012 - 괄호 (Silver IV)

🔗 https://www.acmicpc.net/problem/9012


문제 분석

문제 요약

괄호 문자열이 주어질 때 올바른 괄호 문자열(VPS)인지 판단.

'('')'로만 구성되며, 짝이 정확히 맞으면 YES, 아니면 NO 출력.

제한사항

  • 테스트 케이스 수 T: 1 이상 50 이하
  • 괄호 문자열 길이: 2 이상 50 이하

입출력 예

입력출력
(())()YES
(())())NO
(()())((()))YES
(((()())()NO

핵심 포인트

  • balance 카운터: '(' → +1, ')' → -1
  • 루프 중 balance < 0 이면 즉시 NO (닫는 괄호가 먼저 나온 경우)
  • 최종 balance == 0 이면 YES, 아니면 NO
  • 홀수 길이는 무조건 NO (조기 탈출 최적화)
  • 첫 문자가 '('가 아니거나 마지막 문자가 ')'가 아니면 즉시 NO

헤더 라이브러리

#include <string>

1
2
3
4
5
6
string s;
cin >> s;
s.size();              // 문자열 길이
s.front();             // 첫 번째 문자
s.back();              // 마지막 문자
for(char c : s) { }   // 각 문자 순회
  • front() / back() — 인덱스 접근 없이 양 끝 문자 확인
  • 범위 기반 for 루프로 char 단위 순회

코드 풀이

풀이 1 — balance 카운터 (작성한 코드)

시간복잡도: O(n) — 문자열 한 번 순회

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
#include <iostream>
#include <string>
using namespace std;

string solution(string s)
{
    if(s.size() % 2 != 0) return "NO";
    if(s.front() != '(' || s.back() != ')') return "NO";

    int balance = 0;
    for(char c : s)
    {
        if(c == '(') balance++;
        else balance--;

        if(balance < 0) return "NO";
    }
    return (balance == 0) ? "YES" : "NO";
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while(T--)
    {
        string s;
        cin >> s;
        cout << solution(s) << "\n";
    }
    return 0;
}

홀수 길이·양 끝 문자 체크로 불필요한 순회를 줄임. balance < 0 즉시 탈출로 최적화.

복기

  • 괄호 문제는 스택 또는 balance 카운터 두 방법 모두 가능
  • balance < 0 이 되는 순간 = 닫는 괄호가 여는 괄호보다 먼저 나온 것 → 즉시 NO
  • 최종 balance != 0 = 열린 괄호가 남아있는 것 → NO
  • 홀수 길이 조기 탈출은 선택이지만 코드 명확성에 도움

백준 10828 - 스택 (Silver IV)

🔗 https://www.acmicpc.net/problem/10828


문제 분석

문제 요약

정수를 저장하는 스택을 구현하는 문제.

push X, pop, size, empty, top 명령어를 순서대로 처리하고 결과를 출력.

제한사항

  • 명령어 수 N: 1 이상 10,000 이하
  • push X에서 X: 절댓값 2³¹ 미만의 정수

입출력 예

명령어출력
push 1 
push 2 
top2
size2
empty0
pop2
pop1
pop (비어있을 때)-1
empty1

핵심 포인트

  • stack<int> STL 컨테이너 사용
  • pop / top 명령어 실행 전 반드시 empty() 체크 → 비어있으면 -1 출력
  • empty 명령어 → 비어있으면 1, 아니면 0 출력
  • STL pop()은 반환값이 없음 → 값 확인은 top()pop() 순서

헤더 라이브러리

#include <stack>

1
2
3
4
5
6
stack<int> s;
s.push(x);    // 스택에 x 삽입
s.pop();      // 최상단 원소 제거 (반환값 없음)
s.top();      // 최상단 원소 반환 (제거 안 함)
s.size();     // 원소 개수 반환
s.empty();    // 비어있으면 true
  • pop()top()은 빈 스택에서 호출 시 Undefined Behavior → 반드시 empty() 먼저 확인

#include <string>

  • 명령어를 string으로 읽어 == 비교 (cmd == "push" 등)

코드 풀이

풀이 1 — stack<int> 활용 (작성한 코드)

시간복잡도: O(N) — 명령어 N개 각각 O(1) 처리

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
#include <iostream>
#include <stack>
#include <string>
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    int n;
    cin >> n;

    stack<int> s;
    string cmd;

    for(int i = 0; i < n; i++) {
        cin >> cmd;
        if(cmd == "push") {
            int num;
            cin >> num;
            s.push(num);
        }
        else if(cmd == "pop") {
            if(s.empty()) cout << "-1\n";
            else {
                cout << s.top() << "\n";
                s.pop();
            }
        }
        else if(cmd == "size") { cout << s.size() << "\n"; }
        else if(cmd == "empty") { cout << s.empty() << "\n"; }
        else if(cmd == "top") {
            if(s.empty()) cout << "-1\n";
            else cout << s.top() << "\n";
        }
    }
    return 0;
}

poptopempty() 체크 필수. cout.tie(NULL) — 출력 버퍼 동기 해제로 속도 향상.

복기

  • STL stack::pop()은 반환값 없음 → 값을 읽으려면 top() 먼저, 그다음 pop()
  • 빈 스택에서 pop()·top() 호출은 UB → 문제 요구대로 -1 출력 처리 필수
  • cout.tie(NULL)coutcin 버퍼 동기 해제 (대량 출력 시 속도 차이 있음)

언리얼에서 VS vs Rider — IDE 선택과 사용 경험

언리얼에서 C++ 클래스를 생성할 때 VS와 Rider가 구체적으로 어떻게 다른지 직접 비교


문제 상황

  • 언리얼 클래스 마법사로 새 C++ 클래스를 만든 직후, VS에서 자동완성과 오류 표시가 바로 작동하지 않는 경험이 있었음
  • 파일 자체는 프로젝트에 추가되지만, IDE가 완전히 인식하기까지 솔루션 재로드가 필요한 경우 발생
  • “VS에서는 안 된다”는 인상이 남았고 Rider를 함께 사용하게 된 계기가 됨

배운 점

Visual Studio

  • 클래스 생성 자체는 정상 — 파일이 솔루션에 추가되고 언리얼에도 반영됨
  • 단, 생성 직후 인텔리센스(자동완성·오류 표시)가 즉시 따라오지 않을 수 있음
  • 솔루션 재로드 후에야 IDE 기능이 정상화되는 경우가 있음
  • 디버깅 환경은 강점: 중단점, 호출 스택, 변수 확인 흐름이 익숙하고 안정적

JetBrains Rider

  • .uproject 기준으로 프로젝트를 관리해 새 파일 추가 후 반영이 빠름
  • 생성 직후에도 자동완성·코드 인식이 자연스럽게 붙음 → “추가하고 바로 이어서 작업”이 편함

공통

  • 런타임 에러 발생 시 처음엔 엔진 내부 파일 경로만 보여 당황할 수 있음
  • 호출 스택을 보면 사용자 코드의 정확한 줄 번호 확인 가능

결론

상황추천이유
새 C++ 클래스 추가 후 바로 작업Rider생성 직후 코드 인식·자동완성이 빠르게 붙음
디버깅 / 빌드 흐름VS중단점·호출 스택 등 디버그 환경이 손에 익음
자동완성이 안 붙을 때VS 솔루션 재로드파일 추가 직후 인텔리센스 반응이 늦을 수 있음

핵심 교훈: “VS에서 클래스 생성이 안 된다”가 아니라, 생성 후 IDE 기능이 붙는 속도의 차이였다. 클래스 추가·즉각 작업은 Rider, 디버깅·빌드는 VS — 상황에 맞게 병행하는 것이 효율적.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.