//프로그래머스 문제 풀이 level1 x만큼 간격이 있는 n개의 숫자 publicstaticvoidmain(String[] args) { int x = 2, n = 5; long[] answer = newlong[n]; answer[0] = x; for(int i = 1; i < n; i++) answer[i] = answer[i-1]+x; } }
정답배열의 첫번째 항을 x로 초기화 한 뒤, 등차수열을 만들 듯 이전 항에 x만큼 더하면 된다. 시간복잡도는 \(O(n)\)이다.
문제에서 제시한대로 코드를 짜면 된다. cnt를 0으로 초기화하고, 짝수면 나누기, 홀수면 곱하기 더하기 연산을 하면된다. 중요한 부분은 int를 쓰지 않고 long을 쓴 것을 볼 수 있는데, 이유는 곱하기 연산을 하면서 int값을 초과할 수 있기 때문이다. 필자는 이것 때문에 한번 틀렸었다. 이 문제 정의에서 이 알고리즘의 시간복잡도는 \(O(1)\)이다. 왜냐하면 500이라는 횟수가 최대 실행 횟수이기 때문이다.
//프로그래머스 문제 풀이 level1 최대공약수와 최소공배수 publicstaticvoidmain(String[] args) { int n = 3, m = 12; int[] answer = newint[2]; int min, max; min = Math.min(n, m); max = Math.max(n, m); int big_div = -2, small_mul = -2; for(int i = 1; i <= min; i++) { if(min%i == 0 && max%i == 0) big_div = i; } int temp = max; while(true) { if(temp % min == 0 && temp % max == 0) { small_mul = temp; break; } temp++; } answer[0] = big_div; answer[1] = small_mul; } }
부분부분 보도록 하자
1 2 3 4 5 6 7 8 9 10 11
int n = 3, m = 12; int[] answer = newint[2]; int min, max; min = Math.min(n, m); max = Math.max(n, m); int big_div = -2, small_mul = -2; for(int i = 1; i <= min; i++) { if(min%i == 0 && max%i == 0) big_div = i; }
n과 m중에 크고 작은 값을 각각 min, max에 담았다. 최대공약수는 min값보다 클 수 없으므로 1에서 min까지 보면서 나눌 수 있는 최대를 big_div에 담는다. 여기서 n,m중 더 작은 값을 a라고 하면 시간복잡도는 \(O(a)\)로 볼 수 있다.
1 2 3 4 5 6 7 8 9 10
int temp = max; while(true) { if(temp % min == 0 && temp % max == 0) { small_mul = temp; break; } temp++; }
최소공배수는 max값이상이어야 한다. temp값을 max로 한 뒤, temp를 증가하면서 처음으로 나누어떨어지는 수가 있으면 최소공배수 값을 업데이트하고 반복문을 탈출한다. 이 부분에서도 시간복잡도는 \(O(a)\)라는 것을 알 수 있다. 왜냐하면 최소공배수가 가장 큰 경우가 n*m이기 때문이다. 따라서 총 알고리즘의 시간복잡도는 \(O(a)\)\(a = min(n,m)\)이다.
키패드를 어느 쪽 손으로 눌러야 하는 가에 대한 문제이다. 초기 왼손의 위치는 *에 오른손의 위치는 #에 위치해있다. 1,4,7은 무조건 왼손으로 누르고 3,6,9는 오른손으로 누른다. 손가락은 상하좌우로만 움직일 수 있다. 2,5,8,0은 왼손과 오른손 중 더 가까이 있는 손가락으로 누르며, 만약 두 손가락이 움직이는 거리가 같은 경우 주로 쓰는 손으로 누른다. 눌러야할 번호들이 주어지면 어느쪽 손으로 누르는지 "L"과 "R"로 구성된 문자열로 나타내라.
정답을 담을 StringBuilder buff를 선언한다. 초기 왼손은 *에 있고 오른손은 #에 있을때 이를 각각 10과 11로 지정한다. 그리고 moves를 작성한다. 번거로울 수 있지만, 마땅한 식이 떠오르지 않을 때 빠르게 문제를 풀 수 있다. 행이 시작점을 나타내고 열을 끝나는 점이라고 했을 때, 움직이는 횟수를 기록하였다. 예를들면 1에서 0으로 가기까지는 moves[1][0]에 해당하는 수이므로 4가 된 것을 볼 수 있다. 다음으로 boolean값에 해당하는 isleft를 선언한다. 이는 왼손으로 키패드를 눌러야하는지 나타내는 변수로 초기화는 아무렇게나 해도 상관없다. 필자는 false로 초기화하였다.
논리적으로 어려운 부분은 없다. 1,4,7인경우에는 왼손으로 누르므로 isleft를 true값으로 변경한다. 3,6,9인 경우 false로 바꾼다. 만약 중간에 있는 키패드인 경우 moves 값을 비교하여 판별한다. 만약 값이 같은 경우 어느 손잡이인지 보면 된다. 키패드를 누를 때마다 현재 있어야 하는 위치값을 업데이트 하는 것을 잊지 말자. numbers의 길이를 n이라고 하면 이 알고리즘의 시간복잡도는 \(O(n)\)이다.
테스트
옛날에 멋모르고 인턴에 지원했다가 이 문제만 2-3시간 풀고 포기한 경험이 있다. 그래서 그 때의 안 좋은 감정이 차올랐는데, 이번에는 30분정도 걸렸다. 내가 성장하고 있는 걸 느껴서 기쁘다. 첨언을 하자면 키패드를 자세히 보면 3으로 나머지연산과 나누기 연산을 하면 키패드의 어느 위치에 있는지 쉽게 알 수 있다. 이걸 활용하면 코드를 더 간결하게 만들 수 있을거라 생각한다.