본문 바로가기

카테고리 없음

2023.08.18 TIL - 알고리즘 문제 - 2

문자열을 정수로 바꾸기

문자열로 입력받은 정수를 정수 타입으로 출력하는 문제이다.

import java.util.*;
class Solution {
    public int solution(String s) {
        return Integer.parseInt(s);
    }
}

문제의 조건에 잘못된 값이 입력되는 경우는 없기에 s에 +,-가 포함되더라도 Integer 클래스의 parseInt 메소드를 활용하면 한줄로도 문제를 해결할 수 있다. 이를 사용하지 않는다면 s를 index별로 가른 후 자릿수마다 더하는 방법을 사용해야 할 것이다.

 

 

정수 제곱근 판별

입력받은 정수가 제곱수인지 판별하고, 제곱수라면 제곱근에 1을 더한 수를 제곱해 출력하는 문제이다.

class Solution {
    public long solution(long n) {
        double root = Math.sqrt(n);
        return Math.floor(root)==root?(long)((root+1)*(root+1)):-1;
    }
}

n의 제곱근을 버림한 수를 n의 제곱근과 비교했을 때 다르다면 -1을, 같다면 그 수에 1을 더하고 이를 제곱해 출력하게 하였다. 삼항연산자를 사용하였으나 if를 사용해도 동일한 결과를 얻을 수 있다. 이전에는 sqrt 메소드를 java.lang.Math를 import해 사용했는데, 이들이 자바의 기본 언어에 포함되어 있는 메소드라는 것을 팀원에게 들었고, Math.을 붙일 경우 import하지 않아도 사용할 수 있다는 것을 알게 되었다.

 

 

정수 내림차순으로 배치하기

정수의 각 자릿수를 내림차순으로 배치한 정수를 출력하는 문제이다.

import java.util.*;

class Solution {
    public long solution(long n) {
        long answer = 0;
        String[] str = Long.toString(n).split("");
        PriorityQueue<Long> arr = new PriorityQueue<>(Collections.reverseOrder());
        for (String s:str)
            arr.add(Long.parseLong(s));
        while(!arr.isEmpty()){
            answer=answer*10+arr.poll();
        }
        return answer;
    }
}

특정 순위에 맞춰 데이터를 정렬해 저장해 주는 자료구조인 PriorityQueue를 활용해 정수의 각 자릿수를 모두 저장하였고, 이 자료구조에서 하나씩 값을 빼서 더해주었다. 다른 사람 풀이를 확인한 결과 배열에 내장되어 있는 메소드인 sort()를 활용해 오름차순으로 정렬할 수 있다는 것을 알았다.

 

 

하샤드 수

x의 자릿수의 합으로 x가 나누어질 경우, x를 하샤드 수라 부른다. x가 하샤드 수인지 아닌지를 판별하는 문제이다.

class Solution {
    public boolean solution(int x) {
        int tmp = 0;
        int x1 = x;
        while(x1!=0){
            tmp +=x1%10;
            x1/=10;
        }
        return x%tmp==0;
    }
}

각 자릿수의 합은 이전에 풀었던 코드를 참조해 구현하였다. 대신, 이번에는 입력받은 값 x가 필요하므로 x의 값을 별도의 변수에 저장한 후 활용하였다. 모든 자릿수를 더한 후, x를 그 수로 나눈 나머지가 0과 일치하는지를 출력하였다.

 

 

두 정수 사이의 합

두 정수가 입력되었을 때, 두 수 사이에 있는 모든 정수들의 합을 출력하는 문제이다.

import static java.lang.Math.*;
class Solution {
    public long solution(int a, int b) {
        long answer = 0;
        int big = max(a,b);
        int small = min(a,b);
        for(int i =small;i<=big;i++)
            answer+=i;
        return answer;
    }
}

입력받는 두 정수의 대소 관계가 정의되지 않았기에 큰 수와 작은 수를 판별한 후 저장한 다음, 반복문을 통해 각 수들을 모두 더해주었다. 

다른 사람 풀이를 보니 잊고 있던 등차수열의 합 공식을 사용한 것이 보여 알고리즘과 수학의 중요성을 다시 한번 되새기는 계기가 되었다.

 

 

콜라츠 추측

입력된 수가 짝수라면 2로 나누고, 홀수라면 3을 곱하고 1을 더한다. 콜라츠 추측은 이 과정을 반복할 경우, 모든 수를 1로 만들 수 있다는 추측이다.

class Solution {
    public int solution(int num) {
        int count = 0;
        long tmp = (long)num;
        while(count<=500){
            if (tmp==1) break;
            if (tmp%2==0) tmp/=2;
            else tmp=tmp*3+1;
            count++;
        }
        return count>500?-1:count;
    }
}

num이 짝수일 땐 2로 나누고, 홀수일 땐 3을 곱하고 1을 더해주는 작업을 500번 반복할 때까지, 혹은 수가 1이 될때까지 반복하였다. 그 후, 반복한 수가 500이 넘는다면 -1을, 그렇지 않다면 반복 횟수를 출력하는 형태로 문제를 해결하였다.

문제를 풀 때 정말 애를 먹은 문제였다. num의 조건은 8백만 미만의 정수로, int 타입의 범위인 2억보다 분명히 작은데 자꾸 오답이라는 결과를 받았다. 계산 과정 직후의 수를 모조리 출력한 결과, 어느 순간 숫자가 음수로 바뀌는 것을 확인했는데, 그 이전 수와 비교한 결과 숫자가 너무 커지게 되어 오버플로우가 발생했다는 사실을 알게 되었다. 

애를 먹은 부분은, 같은 팀원은 else 대신 else if를 사용해 2로 나눈 나머지가 1일 때의 조건을 명시했었는데, 그 때는 또 정답이라고 하는 것이었다. 이 또한 모조리 출력을 해 보았는데, 오버플로우가 발생한 후에 2로 나눈 나머지를 확인하는 과정에서 -1을 출력하게 되어 내가 작성한 코드에서는 else문의 계산을 진행했으나 팀원의 코드에서는 해당 계산을 진행하지 않고 계속 동일한 값만 출력하는 것을 발견했다. 제출 시 검증하는 케이스에 오버플로우가 발생할 수 있는 정수는 항상 과정을 500번 이상 반복하게 되어 정답 처리하는 것으로 보이며, num을 long 타입으로 변환한 것이 정확한 답인 것으로 예상한다. 

이를 기술매니저님께 상담하였는데, BigDecimal 변수를 사용하면 모든 문제를 오버플로우 없이 해결할 수 있지만 엄청나게 많은 데이터 공간을 잡아먹기에 타입의 변경은 결국 개발자가 필요에 따라 센스있게 변환하는 감각이 필요하다는 이야기를 들었다.

 

 

서울에서 김서방 찾기

String 배열에서 "Kim"과 동일한 요소의 인덱스를 출력하는 문제이다.

class Solution {
    public String solution(String[] seoul) {
        String answer = "";
        for (int i = 0; i<seoul.length;i++)
            if (seoul[i].equals("Kim")){
                return "김서방은 "+i+"에 있다";
            }
        return "-1";
    }
}

배열 내에 "Kim"이 무조건 존재한다는 조건을 받았기에 String의 메소드 equals를 활용해 일치하는지 확인하였고, 일치할 때 즉시 문구를 출력하도록 하였다. 입력 조건에는 위 코드만으도 문제 없이 출력할 수 있으나 메소드에서는 이를 확인할 수 없기에 에러가 출력된다. 따라서 별도로 for문에서 출력하지 못한 경우 -1을 출력하도록 하였다. 만약 무조건 존재한다는 조건을 받지 못했다면 -1의 자리에 존재하지 않을 때의 출력을 작성하면 될 것이다.