1. 문제의 발단.
- 시간 복잡도를 생각해서 거듭제곱(x^n)을 구할 예정이다.
- 아주 큰 수가 제곱수 안에 있을 경우 94,906,249를 나눠 나머지를 다시 제곱해 줘서 컴퓨터가 표현할 수 있는 수 안에서 결과를 구해야 한다.
- Math.pow()는 사용 금지한다.
2. 시도 1
function efficientPow(baseNum, exponent) {
let result = 1;
for(let i = 0; i < exponent; i++) {
result = result * baseNum;
if(result > 94906249) {
result = result % 94906249;
}
}
return result;
}
- 답은 맞았다.
- 하지만 효율적이지 못했다. 시간 복잡도를 통화하지 못했다.
- 반복문이 아닌 재귀 함수 등을 이용하는 것도 또 다른 방법이 될 수 있지만, 똑같은 방식으로 반복문을 재귀 함수로 고친다고 해도, 시간 복잡도를 줄이지 못할 것이라고 생각했다.
- 그래서 거듭제곱의 특징을 알아보고 시간 복잡도를 줄일 수 있지 않을까?라고 생각했다.
3. 지수법칙
- 위의 식을 이용하면 내가 곱해야 할 지수를 절반으로 줄일 수 있다고 생각했다. 즉 2의 5승 곱하기 2의 5승은 2의 10승과 같다면, 2의 5승까지만 알게 되면 더 이상 2의 6승 등을 알 필요가 없어진다.
4. 시도 2
function efficientPow(baseNum, exponent) {
if(exponent === 0){
return 1;
}
// 재귀의 탈출 조건이 된다.
let halfExponent = efficientPow(baseNum, Math.floor(exponent/2));
// 제곱의 지수의 절반인경우를 구한다.
let result = (halfExponent * halfExponent) % 94906249;
// 만약, 표현할 수 있는 최대 수를 넘기면 나눠서 나머지에 다시 절반인 제곱수를 곱한다.
if(exponent % 2 === 0){
return result;
}else{
return (result * baseNum) % 94906249;
}
// 이후, 지수가 짝수이면 그대로 리턴, 아니라면 다시 곱해서 최대수가 넘으면 사눠서 나머지를 리턴한다.
}
- 성공!
- 정말 절반만 계산해서 시간 복잡도를 크게 떨어뜨릴 수 있었다.
나는 중1 시절 수학을 놨다.
사실 저 지수법칙과도 초면이었다...
역시 또 수학공식을 모르니 생각이 넓게 미치지 못하는 것 같다. 코드를 쓰는 문법에 익숙해지면 알고리듬 공부를 할 때는 수학에 대해 공부하는 것도 나쁘지 않은 전략이 될 것 같다.
'Coding > Today I Learned' 카테고리의 다른 글
2021.08.02(Mon.) <간단한 useEffect의 규칙> (0) | 2021.08.02 |
---|---|
2021.08.01(Sun.) <트리구조를 여행하는 히치하이커들을 위한 안내서 > (0) | 2021.08.02 |
2021.07.30(Fri.) <REST API> (0) | 2021.07.30 |
2021.07.29(Thu.) <HTTP와 네트워크 기초중에 기초> (0) | 2021.07.29 |
2021.07.28(Wen.) <Async & Await의 기초> (0) | 2021.07.29 |