어떤 알고리즘으로 풀어야 할까?

khs·2022년 8월 16일
0

1. 시간 복잡도 정의하기

알고리즘에서 시간 복잡도는 주어진 문제를 해결하기 위한 연산 횟수를 말한다. 일반적으로 수행 시간은 1억 번의 연산을 1초의 시간으로 간주하여 예측한다.

시간 복잡도 유형
1. 빅-오메가 Ω(n) : 최선일 때의 연산 횟수를 나타낸 표기법
2. 빅-세타 θ(n) : 보통일 때의 연산 횟수를 나타낸 표기법
3. 빅-오 O(n) : 최악일 때의 연산 횟수를 나타낸 표기법


ex) 만약 1~100 사이의 숫자에서 무작위로 정한 하나의 숫자를 찾는 코드를 작성한다고 할 때 유형에 따른 시간 복잡도는 아래와 같다.

빅-오메가 표기법의 시간 복잡도는 1번
빅-세타 표기법의 시간 복잡도는 N/2 이므로 50번
빅-오 표기법의 시간 복잡도는 N 이므로 100번


2. 코딩 테스트에서 사용하는 시간 복잡도 유형

코딩 테스트에서는 빅-오 표기법을 기준으로 수행 시간을 계산하는 것이 좋다. 다양한 테스트 케이스를 수행하여 모든 케이스를 통과해야만 합격으로 판단하기 때문에 최악일 때를 염두해야 한다.

ex) N개의 수가 주어졌을 때 이를 오름차순 정렬하는 프로그램을 작성하시오. - 시간 제한 2초, 1 <= N <= 1,000,000

정렬 부분의 학습을 완료하여 버블 정렬과 병합 정렬의 시간 복잡도를 각각 O(n^2), O(nlogn) 임을 알고 있다고 가정했을 때

알고리즘 적합성 평가

  • 버블 정렬 = (1000000)^2 = 1000,000000000 > 200000000 -> 부적합 알고리즘
  • 병합 정렬 = 1000000 * log(1000000) = 약 20000000 < 200000000 -> 적합 알고리즘

버블 정렬은 약 10억 번의 연산 횟수가 필요하므로 이 문제를 풀기에 적합한 알고리즘이 아니라고 판단할 수 있다. 병합 정렬은 약 2000만 번의 연산 횟수로 답을 구할 수 있으므로 문제를 풀기에 적합한 알고리즘이라고 판단할 수 있다.

이와 같이 시간 복잡도 분석으로 사용할 수 있는 알고리즘을 선택할 수 있고 이 범위를 바탕으로 문제의 실마리를 찾을 수 있다.


3. 시간 복잡도를 바탕으로 코드 로직 개선하기

시간 복잡도 도출 기준
1. 상수는 시간 복잡도 계산에서 제외한다.
2. 가장 많이 중첩된 반복문의 수행 횟수가 시간 복잡도의 기준이 된다.

i )

public class 시간복잡도_원리1 {
	public static void main(String[] args) {
    	int N = 10000;
        int cnt = 0;
        for (int i=0; i<N; i++){
        	System.out.println("연산 횟수: "+ cnt++);
        }
    }
}
public class 시간복잡도_원리2 {
	public static void main(String[] args) {
    	int N = 10000;
        int cnt = 0;
        for (int i=0; i<N; i++){
        	System.out.println("연산 횟수: "+ cnt++);
        }
        for (int i=0; i<N; i++){
        	System.out.println("연산 횟수: "+ cnt++);
        }
        for (int i=0; i<N; i++){
        	System.out.println("연산 횟수: "+ cnt++);
        }
    }
}

위 두 코드의 연산 횟수는 3배 차이가 나지만 시간 복잡도 도출에 있어서 일반적으로 상수는 무시하므로 두 코드 모두 시간복잡도는 O(n) 이다.

ii )

public class 시간복잡도_원리3 {
	public static void main(String[] args) {
    	int N = 10000;
        int cnt = 0;
        for (int i=0; i<N; i++){
            for (int j=0; j<N; j++){
                System.out.println("연산 횟수: "+ cnt++);
            }
            for (int j=0; j<N; j++){
                System.out.println("연산 횟수: "+ cnt++);
            }
            for (int j=0; j<N; j++){
                System.out.println("연산 횟수: "+ cnt++);
            }
        }
    }
}

시간복잡도_원리3 클래스 내에는 for문안에 3개의 for문이 있지만 시간 복잡도는 가장 많이 중첩된 반복문을 기준으로 도출하므로 이 코드의 시간 복잡도는 O(n^2) 이다.

profile
권혁상입니다. 행복코딩^_^

0개의 댓글