1️⃣ 알고리즘
1. 알고리즘이란?
- 문제를 해결하기 위한 단계적 절차나 규칙(레시피)
- 예시
1단계: 장바구니 상품 목록을 입력받는다
2단계: 총 금액 변수를 0으로 설정
3단계: 각 상품에 대해 반복:
- 상품의 가격 × 수량을 계산
- 계산 결과를 총 금액에 더함
4단계: IF 총 금액이 50,000원 이상이면
배송비 = 0
ELSE
배송비 = 3,000
5단계: 최종 결제 금액 = 총 금액 + 배송비
6단계: 최종 결제 금액 출력
2. 알고리즘 표현 방법 : 다른 사람에게 전달 / 구현 > 과정을 명확하고 간결하게 표현
1) 의사코드
- 프로그래밍 언어와 유사
- 예시) 최댓값 찾기
FUNCTION findMax(numbers):
max ← numbers[0] // 첫 번째 값 > max = 이게 제일 크다고 치자.
FOR i = 1 TO length(numbers) - 1 // [1] ~ [마지막]
IF numbers[i] > max THEN
max ← numbers[i] // 최댓값 > max
END IF
END FOR
RETURN max
END FUNCTION
2) 자연어 표기법
- 비전문가도 이해 가능
- 문장이 모호해질 수 있으므로 정확한 표현에 신경 써야 함
- 예시) 최댓값 찾기
1. 첫 번째 숫자를 최댓값으로 저장한다.
2. 두 번째 숫자부터 마지막 숫자까지 순서대로 확인한다.
- 현재 숫자가 저장된 최댓값보다 크면, 현재 숫자를 최댓값으로 갱신한다.
3. 모든 숫자를 확인한 후, 최댓값을 반환한다.
2️⃣ 좋은 알고리즘
1. 조건
1) 정확성: 정확하게 동작하는가
- 입력한 값에 대해 올바른 결과
- 정해진 단계를 따라 실행, 반드시 멈추는 시점 O
- 같은 입력 값이면 항상 같은 값 정확성(정확하게 동작)
2) 효율성
- 시간 복잡도: 실행시간이 너무 오래 걸리지 X
- 공간 복잡도: 메모리를 적절하게 사용
3) 명확성: 이해하기 쉬운가
- 각 단계가 명확하고 이해하기 쉬워야 함
- 다른 사람도 읽고 이해 O
- 주석으로 설명 추가하면 좋음 명확성(이해하기 쉬운가)
4) 확장성: 실용적이고 관리하기 좋은가
- 다양한 상황에서 사용 O
- 나중에 수정하거나 개선하기 쉬운가
3️⃣ 알고리즘 성능 분석
1. 성능 분석이란
- 얼마나 효율적으로 동작하는지 측정 방법
- 기준: 시간(실행 속도) + 공간(메모리 사용량)
2. 시간복잡도: 알고리즘이 문제를 해결하는데 얼마나 많은 시간이 필요한지 표현하는 방법
1) 빅오(Big-O) 표기법
- 시간 복잡도를 수학적으로 표현하는 방법
- 입력 데이터 크기가 늘어날 때 실행 시간이 어떤 비율로 증가하는지 표현
- 입력 데이터 크기에 따라 실행 시간 증가 추세 표현

3. 시간 복잡도 구하기
1) 명령문 개수 계산
- 반복문, 조건문, 대입문 등 각각의 명령문이 실행되는 횟수 계산
- 각 줄의 실행 횟수를 더하여 전체 실행 획수를 구한다
- 예시
public class TimeComplexityExamples {
/**
* O(1) - 상수 시간 복잡도
* 입력값 n에 상관없이 항상 동일한 시간이 걸립니다.
* 단순 출력문 하나만 실행되므로 실행 시간이 일정합니다.
*/
public void constantTime(int n) {
System.out.println(n); // 단 한 번의 연산만 수행
}
/**
* O(n) - 선형 시간 복잡도
* 입력값 n에 비례하여 실행 시간이 증가합니다.
* n이 2배가 되면 실행 시간도 약 2배가 됩니다.
*/
public void linearTime(int n) {
for(int i = 0; i < n; i++) {
System.out.println(i); // n번 실행됨
}
}
/**
* O(n²) - 제곱 시간 복잡도
* 입력값 n의 제곱에 비례하여 실행 시간이 증가합니다.
* n이 2배가 되면 실행 시간은 4배가 됩니다.
*/
public void quadraticTime(int n) {
// 외부 루프: n번 반복
for(int i = 0; i < n; i++) {
// 내부 루프: 각 i에 대해 n번 반복
for(int j = 0; j < n; j++) {
System.out.println(i + j); // n * n = n² 번 실행됨
}
}
}
}
2) 가장 큰 항만 남기기
- 빅오 표기법에서 큰 항만 고려하는 이유
: 입력 크기(n)가 매우 커질 때는 작은 항들의 영향력 미미
: 상수항은 실제 실행 환경에 따라 달라질 수 있어 제외
: 증가 추세를 파악하는 것이 목적 - 예시) 입력 데이터 크기가 n일 때 명령어 실행횟수가 T(n)인 경우 시간 복잡도 계산
T(n) = 5n³ + 100n² + 200n + 1000
단순화 과정
1. 최고차항 선택: 5n³
2. 계수 제거: 5
3. 다른 항 제거: n², n, 상수항 제거
4. 최종 표기: O(n³)
- 예시) 1부터 n까지 합을 구하는 알고리즘 / 실행 횟수 분석 및 시간 복잡도 계산
/* 1부터 n까지의 합을 구하는 알고리즘
실행 횟수 분석 및 시간 복잡도 계산 */
int sum = 0; // 초기화: 대입 연산 1회
/* 반복문 실행 분석
- 초기화 (i = 0): 대입 연산 1회
- 조건 검사 (i < n): 조건 연산 n+1회
- 증감식 (i++): 증감 연산 n회 */
for(int i = 0; i < n; i++) {
sum += i; // 덧셈 연산 n회
}
System.out.println(sum); // 출력: 함수실행 1회
/* 전체 실행 횟수 계산
= 1 + 1 + (n+1) + n + n + 1
= 3n + 4
시간 복잡도: O(n)
- 실행 횟수가 n에 비례하여 선형적으로 증가 */
4️⃣ 더 좋은 알고리즘
1. 시간 복잡도 차이
- 배열의 모든 원소의 합과 최댓값을 구하기 위해
반복문을 한 번만 사용 vs 반복문 두 번 사용
public class SimpleTimeComplexity {
public static void main(String[] args) {
int n = 10000;
int[] numbers = new int[n];
// 배열 초기화
for (int i = 0; i < n; i++) {
numbers[i] = i + 1;
}
// 방법 1: 하나의 반복문으로 두 연산 수행
System.out.println("방법 1: 하나의 반복문");
int sum1 = 0;
int max1 = 0;
for (int i = 0; i < n; i++) {
sum1 += numbers[i]; // 합계 구하기
if (numbers[i] > max1) {
max1 = numbers[i]; // 최댓값 찾기
}
}
// 방법 2: 두 개의 반복문으로 각각 연산 수행
System.out.println("방법 2: 두 개의 반복문");
int sum2 = 0;
for (int i = 0; i < n; i++) {
sum2 += numbers[i]; // 합계 구하기
}
int max2 = 0;
for (int i = 0; i < n; i++) {
if (numbers[i] > max2) {
max2 = numbers[i]; // 최댓값 찾기
}
}
}
}
- 둘 다 O(n)
- 과도하게 하나의 반복문에 모든 로직 처리할 필요 X / 코드의 가독성과 유지보수성을 고려해 분리 O
2. 1~1000까지 합 구하기

- 예시
public class SumAlgorithms {
// 방법 1: 단순 반복문 - O(n)
public static int sumLoop(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
total += i;
}
return total;
}
// 방법 2: 가우스 공식 - O(1)
public static int sumGauss(int n) {
return n * (n + 1) / 2;
}
public static void main(String[] args) {
int n = 1000;
// 각 방법의 실행 시간 측정을 위한 변수
long startTime, endTime;
// 방법 1: 반복문
startTime = System.nanoTime();
int result1 = sumLoop(n);
endTime = System.nanoTime();
System.out.println("반복문 결과: " + result1);
System.out.println("실행 시간: " + (endTime - startTime) + " ns");
// 방법 2: 가우스 공식
startTime = System.nanoTime();
int result2 = sumGauss(n);
endTime = System.nanoTime();
System.out.println("\n가우스 공식 결과: " + result2);
System.out.println("실행 시간: " + (endTime - startTime) + " ns");
}
}
3. 시간 복잡도 비교 차트
- Y축: 연산량, X추기: n의 크기

- 빅오 시간 복잡도에 따른 실제 실행 시간 비교표(N=10억)


- 시간 제한에 따른 알고리즘 가능 여부

5️⃣ 알고리즘 유형
1. 구현 & 시뮬레이션
1) 구현 문제: 문제의 요구사항을 실제 동작하는 코드로 구현하는 능력
시뮬레이션 문제: 문제에서 요구하는 시나리오, 규칙, 절차를 차례대로 실행하는 능력
2) 특징
- 코딩 테스트에서 가장 기본이 되는 문제 유형
- 구현의 정확성
- 요구사항을 빠짐없이 코드로 옮기는 것
- 문제의 조건과 제약을 정확히 이해, 처리
- 꼼꼼함 / 중간 결과 검증 / 문제의 전체 흐름 파악 중요
3) 주요 유형
- 단순 구현 : 주어진 알고리즘이나 규칙을 그대로 코드로 옮기는 것
→ 날짜 계산, 문자열 처리, 진법 변환 - 완전 시뮬레이션 : 문제에서 제시된 과정을 처음부터 끝까지 실행하여 결과를 도출
→ 게임 진행, 주사위/카드/보드 시뮬레이션 - 상태 변화 시뮬레이션 : 특정 조건에 따라 시스템의 상태가 변화하는 과정을 구현
→ 로봇 이동, 뱀 게임 - 규칙 찾기 : 문제의 숨겨진 규칙을 찾아 이를 코드로 구현
→ 달팽이 배열, 패턴 문제
2. 완전 탐색 : 모든 경우의 수를 전부 시도해서 정답을 찾는 방식
1) 특징
- 정답을 놓칠 가능성이 없음
- 대신 입력 크기가 작을 때만 유리
- 구현이 비교적 단순
2) 구현 방법
- 반복문 이용
- 재귀 함수 이용 = 자기 자신을 다시 호출하는 함수 + 종료조건 필수
3) 대표 유형
- 순열 / 조합 계산
→ N개 중 K개를 고르는 모든 조합, N개 전부를 나열하는 모든 순열 - 부분집합 계산
→ 부분집합의 합으로 특정 값을 만드는 모든 경우 확인 - 그래프 전체 탐색
→ 모든 경로 찾기, 모든 노드 방문 시뮬레이션, DFS/BFS를 통한 모든 가능성 확인
3. 그리디 알고리즘 : 매 순간 가장 좋아 보이는 선택을 하는 방식
1) 특징
- 구현이 쉽고 빠름
2) 적용 조건
- 탐욕 선택 속성 : 지금 제일 좋아 보이는 선택을 해도 괜찮은 성질
- 최적 부분 구조 : 작은 문제도 최선이어야 함
3) 대표 문제 유형
- 거스름돈 문제
> 동전 단위가 특정 조건에 부합할 때, 큰 단위 동전부터 사용 - 회의실 배정
> 종료 시간이 빠른 회의부터 배정하는 방식 / 최대 개수를 찾는 문제 - 최소 신장 트리 (Kruskal, Prim) : 최소 비용
> 크루스칼(Kruskal) - 싼 것부터 고름(사이클x) , 프림(Prim) 알고리즘 - 최소 비용으로 넓혀가기
4. 백트래킹
1) 개념
- 완전 탐색 기반 + 조건 불만족은 미리 배제
- 탐색 효율 높이는 기법
2) 특징
- 재귀로 구현하는 경우가 많음
- 탐색 범위를 크게 줄일 수 있음
3) 적용조건
- 상태 공간 트리 구성 가능성 : 문제 해결 과정 > 트리 형태 / 단계별 선택지를 명확하게 정의
- 유망성 판단 기준: 더 진행할 가치가 있는지 판단
- 가지치기 효율성: 조건 불만족 제외했을 때 탐색 범위가 줄어야 함 / 조건 검사가 복잡x
4) 대표 문제
- N-Queen : 퀸이 서로 공격하지 않도록 배치하는 경우의 수 찾기
- 스도쿠
- 조건 있는 부분집합 문제
5. 분할 정복
1) 개념
- 문제를 비슷한 하위 문제로 나누고
- 각각 해결한 뒤 결과를 합침
2) 구조
- 분할 → 정복 → 병합
- 각 부분 문제는 독립접
3) 적용 조건
- 분할 가능성
- 하위 문제의 독립성
- 병합 가능성
4) 대표 문제 유형
- 병합 정렬
- 퀵 정렬
- 이진 탐색
6. 동적 계획법
1) 개념
- 작은 문제의 해를 저장해두고 재사용
- 중복 계산 제거
2) 특징
- Top-Down 방식(메모이제이션) 또는 Bottom-up 방식(타뷸레이션)으로 구현
- 점화식(Recurrence Relation)을 올바르게 세우는 것이 핵심
3) 적용 조건
- 최적 부분 구조
- 중복되는 부분 문제
4) 대표 문제 유형
- 피보나치 수열
- 배낭 문제
- LIS (최장 증가 부분 수열)
- 최단 경로
'🔌 SPARTA > Courses' 카테고리의 다른 글
| 배열과 컬렉션 (1) | 2026.01.28 |
|---|---|
| 완전 탐색과 그리디 알고리즘 (1) | 2026.01.27 |
| 걷기반 4회차: 상속과 제네릭, enum (1) | 2026.01.23 |
| 걷기반 3회차: 생성자, this, Order (0) | 2026.01.21 |
| 걷기반 2회차: 배열(Array와 List) (0) | 2026.01.16 |