티스토리 뷰

 문제를 풀고 제출했는데 시간 초과! 완전 탐색을 하기 위해 재귀를 이용하긴 했지만 꼭 필요한 경우만 돌았는데도 시간 초과라 의아했다. 완전 탐색이 아닌 다른 방법으로 푸는 방법도 있겠지만 Math.max() 메서드 사용이 시간 지연의 원인일 수도 있겠다는 생각이 들었다. 대충 검색을 해보니 Math.max()의 성능이 그리 좋지 않다는 것을 확인할 수 있었다. 그래서 삼항 연산자, 비교 연산자, Math.max()를 이용한 최댓값 구하기의 속도를 비교해 보았다.

public class Test {

	public static void main(String[] args) {

		long start = 0, end = 0;
		long[] time = new long[4];
		int fastest = 0;
		
		int[] arr = new int[100_000_000];;
		int max = 0;
		
		System.out.println("CASE :");
		System.out.println("1. 삼항 연산자를 사용한 경우1의 소요 시간 (max = (max <= arr[i]) ? arr[i] : max;)");
		System.out.println("2. 삼항 연산자를 사용한 경우2의 소요 시간 (max = (max >= arr[i]) ? max : arr[i];)");
		System.out.println("3. 비교 연산자를 사용한 경우의 소요 시간 (if(max < arr[i]) 	max = arr[i];)");
		System.out.println("4. Math.max()를 사용한 경우의 소요 시간 (내부적으로 삼항연산자 사용)");
		System.out.println();
		System.out.println("		 1	 2	 3	 4	  Fastest Case	   % to case 4");
		System.out.println();
		
		for (int k = 0; k < 30; k++) {
			fastest = 0;
			System.out.print("Test#" + (k+1) + "		");
			for (int i = 0; i < arr.length; i++)
				arr[i] = ((int) (Math.random() * Integer.MAX_VALUE) + 1);

			// CASE 1:
			max = 0;
			start = System.currentTimeMillis();
			
			for (int i = 0; i < arr.length; i++) 
				max = (max <= arr[i] ? arr[i] : max);
			
			end = System.currentTimeMillis();			
			time[0] = end - start;
			System.out.print(time[0] + "	");

			
			// CASE 2:
			max = 0;
			start = System.currentTimeMillis();
			
			for (int i = 0; i < arr.length; i++)
				max = (max >= arr[i] ? max : arr[i]);
			
			end = System.currentTimeMillis();			
			time[1] = end - start;
			System.out.print(time[1] + "	");

			
			// CASE 3:
			max = 0;
			start = System.currentTimeMillis();
			
			for (int i = 0; i < arr.length; i++)
				if (max < arr[i])
					max = arr[i];
			
			end = System.currentTimeMillis();			
			time[2] = end - start;
			System.out.print(time[2] + "	");

			
			// CASE 4:
			max = 0;
			start = System.currentTimeMillis();
			
			for (int i = 0; i < arr.length; i++) {
				max = Math.max(arr[i], max);
			}
			
			end = System.currentTimeMillis();
			time[3] = end - start;
			System.out.print(time[3] + "		");
			
			// 가장 빠른 경우 찾기
			for (int i = 1; i < time.length; i++) {
				if(time[i] < time[fastest])
					fastest = i;
			}
            
			System.out.print((fastest+1)+"	");
			System.out.printf("	%d %%", (int)(100.0 * time[fastest] / time[3]));
			System.out.println();
		}
	}
}

 삼항 연산자에서 대입 값의 위치에 따라 차이가 있는지 궁금해서 CASE 1과 CASE 2로 비교하고,  비교 연산자를 이용하는 경우(CASE 3), Math.max() 메서드를 이용하는 경우(CASE 4)로 두고 테스트를 해보았다. 테스트 케이스마다 배열에 1억 개의 값을 생성해 비교했다.

CASE :
1. 삼항 연산자를 사용한 경우1의 소요 시간 (max = (max <= arr[i]) ? arr[i] : max;)
2. 삼항 연산자를 사용한 경우2의 소요 시간 (max = (max >= arr[i]) ? max : arr[i];)
3. 비교 연산자를 사용한 경우의 소요 시간 (if(max < arr[i]) 	max = arr[i];)
4. Math.max()를 사용한 경우의 소요 시간 (내부적으로 삼항연산자 사용)

		 1	 2	 3	 4	  Fastest Case	   % to case 4

Test#1		250	321	328	438		1		57 %
Test#2		297	399	429	404		1		73 %
Test#3		219	276	348	501		1		43 %
Test#4		234	242	234	437		1		53 %
Test#5		219	252	234	391		1		56 %
Test#6		219	237	235	375		1		58 %
Test#7		234	254	219	390		3		56 %
Test#8		235	252	234	375		3		62 %
Test#9		235	243	235	390		1		60 %
Test#10		228	247	225	391		3		57 %
Test#11		250	238	236	399		3		59 %
Test#12		220	246	235	390		1		56 %
Test#13		469	363	250	391		3		63 %
Test#14		388	476	269	391		3		68 %
Test#15		344	408	483	416		1		82 %
Test#16		218	314	391	516		1		42 %
Test#17		219	251	250	485		1		45 %
Test#18		234	241	234	375		1		62 %
Test#19		218	247	234	375		1		58 %
Test#20		235	238	235	375		1		62 %
Test#21		219	238	234	391		1		56 %
Test#22		250	238	234	375		3		62 %
Test#23		218	250	235	390		1		55 %
Test#24		234	236	234	391		1		59 %
Test#25		234	242	234	391		1		59 %
Test#26		317	252	223	390		3		57 %
Test#27		313	330	291	390		3		74 %
Test#28		282	347	377	405		1		69 %
Test#29		234	305	344	434		1		53 %
Test#30		235	241	234	437		3		53 %

 결과는 1 < 3 < 2 <<< 4의 순서로 시간이 오래 걸렸다. CASE 1과 CASE 2를 비교했을 때 거의 매번 CASE 1의 경우가 빨랐지만 조건문에서 분기해서 대입 값을 결정하고 해당 값을 대입하는 데 어떤 점이 다른지 모르겠다. (값이 유사할 때 비트 전환이 더 빠르다고 하면 모를까) 테스트 전 내 예상은 'CASE 3가 가장 빠를 것이다'였다. 그 이유는 조건문에서 값을 비교하는 상황은 같지만 false 인 경우 대입 과정이 수행되지 않기 때문이었다. 하지만 CASE 3 보다 CASE 1이 빠른 경우가 많았다.

		 1	 2	 3	 4	  Fastest Case	   % to case 4

Test#1		188	245	250	422		1		44 %
Test#2		219	240	219	391		1		56 %
Test#3		242	255	224	415		3		53 %
Test#4		284	262	260	555		3		46 %
Test#5		295	263	242	547		3		44 %
Test#6		219	241	476	1014		1		21 %
Test#7		219	233	282	437		1		50 %
Test#8		242	321	235	518		3		45 %
Test#9		225	247	218	375		3		58 %
Test#10		227	262	240	394		1		57 %
Test#11		219	232	219	391		1		56 %
Test#12		250	238	235	390		3		60 %
Test#13		219	237	219	391		1		56 %
Test#14		329	498	250	406		3		61 %
Test#15		234	331	259	394		1		59 %
Test#16		411	376	360	437		3		82 %
Test#17		360	350	453	406		2		86 %
Test#18		268	358	301	394		1		68 %
Test#19		406	520	320	385		3		83 %
Test#20		250	322	312	391		1		63 %
Test#21		241	237	219	419		3		52 %
Test#22		219	227	225	390		1		56 %
Test#23		267	238	219	371		3		59 %
Test#24		266	253	219	374		3		58 %
Test#25		219	249	208	390		3		53 %
Test#26		223	247	219	375		3		58 %
Test#27		250	237	238	372		2		63 %
Test#28		261	254	223	393		3		56 %
Test#29		344	332	273	406		3		67 %
Test#30		328	328	263	399		3		65 %

 한 번 더 돌려보았다. CASE 3가 가장 빠른 경우가 늘었고, CASE 2가 가장 빠른 경우가 등장했다. 결론은 CASE 1, 2, 3는 큰 차이가 있다고 보기는 어려울 것 같고, 매번 Math.max() 함수를 호출하는 CASE 4는 확실히 느리다. 코드가 깔끔해 보이고 왠지 효율적으로 구현되어있을 것 같아서 생각 없이 사용해왔던 것을 반성해본다. 

 

코딩테스트 시간이 종료되어 변경된 코드를 실행해보진 못했지만, 오늘도 하나 배웠다.

댓글