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 이하의 자연수
입출력 예
| arr | divisor | return |
|---|---|---|
| [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 | |
| top | 2 |
| size | 2 |
| empty | 0 |
| pop | 2 |
| pop | 1 |
| pop (비어있을 때) | -1 |
| empty | 1 |
핵심 포인트
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;
}
pop과top은empty()체크 필수.cout.tie(NULL)— 출력 버퍼 동기 해제로 속도 향상.
복기
- STL
stack::pop()은 반환값 없음 → 값을 읽으려면top()먼저, 그다음pop() - 빈 스택에서
pop()·top()호출은 UB → 문제 요구대로-1출력 처리 필수 cout.tie(NULL)은cout과cin버퍼 동기 해제 (대량 출력 시 속도 차이 있음)
언리얼에서 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 — 상황에 맞게 병행하는 것이 효율적.