관리 메뉴

개발공부기록

Java - 양수의 개수와 덧셈, 문자열 내림차순으로 배치하기, 부족한 금액 계산하기, 문자열 다루기 기본 / SQL(MySQL) - 입양 시각 구하기, 자동차 종류별 특정 옵션이 포함된 자동차 수 구하기 본문

기타 개발 공부/온라인 코딩 테스트 회고

Java - 양수의 개수와 덧셈, 문자열 내림차순으로 배치하기, 부족한 금액 계산하기, 문자열 다루기 기본 / SQL(MySQL) - 입양 시각 구하기, 자동차 종류별 특정 옵션이 포함된 자동차 수 구하기

소소한나구리 2025. 3. 10. 13:25
728x90

Java

양수의 개수와 덧셈

문제

  • 프로그래머스 - https://school.programmers.co.kr/learn/courses/30/lessons/77884
  • 두 정수 left와 right가 매개변수로 주어질 때 left 부터 right 까지의 모든 수들 중에서 약수의 개수가 짝수인 수는 더하고, 약수의 개수가 홀수인 수는 뺀 수를 return하는 함수 완성

제한조건

  • 1 <= left <= right <= 1,000

입출력 예시

나의 풀이

class Solution {
    public int solution(int left, int right) {
        
        int answer = 0;

        for (int i = left; i <= right; i++) {
            int count = 0;

            for (int j = 1; j <= i; j++) {
                if (i % j == 0) {
                    count++;
                }                                                           
            }
            
            answer += count % 2 == 0 ? i : -i;
        }
        return answer;
    }
}
  • 수학을 잘 모르기 때문에 단순히 left 부터 right 까지의 수를 차례로 사용해야하므로 for 문을 사용하였다, 이 때 마지막 수인 right도 사용해야 하므로 i <= right로 조건문을 입력하였다.
  • 첫 번째 반복문의 i의 값이 약수의 개수를 계산해야할 값이므로 다시한번 반복문을 통해서 i의 값을 1부터 i의 값까지 1씩 증가시키며 나머지 연산을 수행하고 나누어 떨어지면 count++을 통해 개수를 증가시켰다.
  • 조건에 약수의 개수가 짝수인 수는 더하고 약수의 개수가 홀수인 수는 빼라는 요구조건에 따라 삼항 연산자로 값을 연산한 후 반환시켜서 문제를 해결했다.

다른 풀이

class Solution {
    public int solution(int left, int right) {
        int answer = 0;

        for (int i=left;i<=right;i++) {
            //제곱수인 경우 약수의 개수가 홀수
            if (i % Math.sqrt(i) == 0) {
                answer -= i;
            }
            //제곱수가 아닌 경우 약수의 개수가 짝수
            else {
                answer += i;
            }
        }

        return answer;
    }
}
  • 접근법은 비슷한 것 같은데, 약수를 구하고자 하는 수의 제곱수를 나누었을 때 나머지가 0이면 약수의 개수가 홀수라는 사실을 처음알게 되었다
  • 이러면 반복문을 한번더 강제적으로 사용하지 않기 때문에 성능이 좋아지므로 알아두면 좋은 것 같다.

문자열 내림차순으로 배치하기

문제

  • 프로그래머스 - https://school.programmers.co.kr/learn/courses/30/lessons/12917
  • 주어진 문자열의 요소를 큰것부터 작은 순으로 정렬해 새로운 문자열을 리턴하는 함수를 완성
  • 문자열은 영문 대소문자로만 구성되어 있으며 대문자는 소문자보다 작은 것으로 간주함

제한조건

  • 주어진 문자열은 길이가 1이상인 문자열임

입출력 예시

나의 풀이

class Solution {
    public String solution(String s) {
        char[] charArr = s.toCharArray();
        Arrays.sort(charArr);

        for (int i = 0; i < charArr.length / 2; i++) {
            char temp = charArr[i];
            charArr[i] = charArr[charArr.length - i - 1];
            charArr[charArr.length - i - 1] = temp;
        }


        return new String(charArr);
    }
}
  • 문자열을 문자 배열로 변환해서 정렬 로직이 최적화 되어있는 Arrays.sort()를 사용하여 오름차순으로 정렬한 다음 내림차순으로 정렬을 위해 문자 배열을 반복문으로 뒤집었다.
  • 이때 반복문을 문자 배열의 절반만큼만 반복해도 되는데, 그 이유는 한번 반복할 때마다 배열의 맨 처음과 맨 끝에 있는 값을 서로 바꿔주기 때문이다.
  • 즉, 배열의 첫 번째 값과 맨 끝에 값을 교환하고 다음 반복문에서는 두 번째 값과 맨 끝에서 두 번째 값을 비교하게 되면서 반복 횟수를 줄일 수 있게 된다.
  • 실제로 이렇게 접근할 때 처음에는 반복문을 끝까지 해서 뒤집었지만 이 효율적인 방법은 검색을 통해서 알게 되었다

다른 풀이

class Solution {
    public String solution(String s) {
        String[] strArr = s.split("");
        Arrays.sort(strArr, Collections.reverseOrder());
        StringBuilder sb = new StringBuilder();
        for (String str : strArr) {
            sb.append(str);
        }

        return sb.toString();
    }
}
  • 주어진 문자열을 split("")으로 문자열을 한 단어씩 분할하여 문자열 배열로 만들어서, Arrays.sort(문자열 배열, Collections.reverseOrder())를 통해 문자열 배열을 내림차순으로 정렬 한다
  • 내림차순으로 정렬된 문자열 배열을 하나의 문자열로 합치기 위해 StringBuilder를 사용하여 append로 각 요소를 하나의 문자열로 합치고 반환 타입이 String이므로 toString()으로 변환한다
    • 이때 StringBuilder를 사용하지 않고 String.join("", strArr)을 통해서 문자열 배열을 모두 합칠 수도 있으며 코드가 간결하여 자주 사용한다고 한다
    • join()은 첫 번째 인자에 구분자, 두 번째 인자에 합칠 문자열 배열을 입력하여 구분자로 문자열 배열의 요소를 합치는 메서드인데, 지금 처럼 첫 번째 인자에 빈 문자열을 입력해주면 단순히 문자열 배열을 순서대로 하나의 문자열로 합치는 결과를 얻을 수 있다
    • join()도 내부적으로 StringBuilder를 사용하기 때문에 성능차이는 없으므로 문자열 배열의 요소를 하나로 합칠 때 유용하게 사용할 수 있을 것 같다
  • ai툴에게 문의한 결과 이 방법은 split()을 할 때 오버헤드가 발생할 수 있으므로 나의 풀이의 방법이 해당 방법보다 성능이 더 좋다고 한다.
class Solution3 {
    public String solution(String s) {
        return s.chars().mapToObj(num -> (char) num)
                .sorted(Collections.reverseOrder())
                .map(String::valueOf)
                .collect(Collectors.joining());
    }
}
  • Stream API를 활용한 풀이로 문자열을 chars() 메서드를 활용하여 각 문자열의 단어를 아스키코드로 변환한 스트림으로 생성한다.
  • 그 이후 mapToObj()를 각 아스키 코드 값을 문자로 변환한 다음 Collections.reverseOrder()를 통해 내림차순으로 정렬하고, .map을 통해 각 요소를 String으로 변환한다.
  • 그다음 최종연산인 collect()를 통해서 Collectors.joining()으로 문자열인 각 요소를 합쳐서 반환한다.
  • 풀이의 3가지 방식 모두 시간복잡도는 동일하지만 스트림 API를 활용하는 방법이 코드는 간결해보여도 가장 성능이 느리다
  • sorted()를 사용하기 위해 객체로 변환하는 과정과 각 요소를 다시 String으로 변환하는 과정, 그리고 그 문자열들을 하나의 문자열로 합치는 과정으로 중간연산의 과정이 위 2가지의 방식보다 더 많기 때문이다.

부족한 금액 계산하기

문제

  • 프로그래머스 - https://school.programmers.co.kr/learn/courses/30/lessons/82612
  • 시설을 이용할 때마다 이용료인 price가 N배만큼 증가할 때 제시되는 count의 횟수 만큼 이용했을 때 본인이 가지고 있는 금액인 money에서 얼마가 모자라는지 return 하는 함수를 완성
  • 금액이 부족하지 않으면 0을 return
  • 이용료가 만약 100원이고 3번 이용했다면 100, 200원, 300원으로 이용요금이 올라감

제한조건

  • price: 1 ~ 2,500의 자연수
  • money: 1 ~ 1,000,000,000의 자연수
  • count: 1 ~ 2,500의 자연수

입출력 예시

나의 풀이

class Solution {
    public long solution(int price, int money, int count) {
        
        long sumPrice = 0;
        for (int i = 1; i <= count; i++) {
            sumPrice += (long) price * i;    
        }
        
        return money - sumPrice >= 0 ? 0 : Math.abs(money - sumPrice);
    }
}
  • count번 시설을 이용했을 때의 금액을 구하기 위해 반복문을 활용하였다.
  • 처음 가격인 price에 반복 횟수만큼 i를 곱한 값을 count번 더해서 count만큼 시설을 이용했을 때 비용을 계산했다.
  • 이후 3항연산자를 이용하여 내가 가진돈과 계산된 비용을 뺄쎔 연산하여 내 돈이 남으면 0을 return하고 내돈이 부족하면 얼마나 부족한지 절대값으로 반환하기 위해 Math.abs()함수를 사용하여 값을 반환시켜 문제를 해결했다
  • Math.abs를 쓰지 않고 -를 곱해서 반환해도 되고 그냥 명시적으로 sumPrice - money로 반환하는 등 조건을 입력하는 방법은 다양하다

다른 풀이

class Solution {
    public long solution(long price, long money, long count) {
        return Math.max(price * (count * (count + 1) / 2) - money, 0);
    }
}
  • 문제에서 메서드의 매개변수가 int이지만 매개변수를 처음부터 long으로 받아버리면 어차피 더 작은 int 타입은 들어올 수 있게 된다.
  • 여기서는 등차수열 합 공식을 활용하여 놀이기구를 이용했을 때의 총 비용을 구했다
    • price * (count * (count + 1) / 2)
  • 그 이후 구해진 금액과 내가 가진 돈인 money를 제외하게 되었을 때 내가가진 돈이 많으면 음수가되고, 금액이 부족하면 부족한 금액이 구해진다
  • Math.max()메서드는 주어진 2개의 인자 중 큰 값을 반환하기 때문에 만약 음수인 경우 0이 더 크므로 0이 반환되고, 금액이 부족한 경우 부족한 금액이 0보다 더 크므로 그대로 값이 반환되게 된다.

문자열 다루기 기본

문제

제한조건

  • 문자열의 길이는 1 ~ 8이며 영문 알파벳 대소문자 혹은 0 ~ 9까지의 숫자로 이루어져있음

입출력 예시

나의 풀이

class Solution {
    public boolean solution(String s) {

        if (s.length() != 4 && s.length() != 6) {
            return false;
        }

        char[] charArr = s.toCharArray();
        for (char c : charArr) {
            if (c - 48 > 10) {
                return false;
            }
        }
        return true;
    }
}
  • 먼저 첫 번째 예외처리를 하기 위해서 길이가 4, 6이 아닌 문자열인 경우 바로 false를 반환하고, 아스키 코드값을 활용하기 위해 검증을 넘어간 문자열은 toCharArray()를 활용하여 문자 배열로 변환했다.
  • 여기서 문자 배열을 순회하여 각 문자에 -48 연산을 한 값이 10보다 크면 숫자인 문자열이 아니므로 바로 더 순회할 필요 없이 바로 return을 반환하도록 하였고, 순회를 정상적으로 돌면 ture를 반환하도록 하여 문제를 해결했다.

다른 풀이

class Solution {
  public boolean solution(String s) {
    return (s.length() != 4 && s.length() != 6) || (s.split("[0-9]").length > 0) ? false:true;
  }
}
  • 확실히 문자열은 정규식을 활용하면 매우 간단히 문자열을 다룰 수 있다.
  • 3항연산자의 조건으로 문자열의 길이가 4와 6이 아니고 s를 0 ~ 9 사이의 숫자로 나누었을 때 길이가 1 이상이면 숫자값이 아닌 다른 문자열이 들어있는 것이므로 false를 반환하고 그 외의 상황에서는 true를 반환하는 방식으로 해결하는 풀이가 매우 신선했다.
class Solution {
  public boolean solution(String s) {
        if (s.length() == 4 || s.length() == 6) return s.matches("(^[0-9]*$)");
        return false;
  }
}

return s.matches("^(\\d{4}|\\d{6})$");
return s.matches("[0-9]{4}|[0-9]{6}");
  • 이 풀이 처럼 matches를 활용하여 문자열이 정규식과 일치하는지 여부를 반환할 수도 있다
  • 길이 검증조차도 정규식으로 가능하기 때문에 어느정도 기본적인 정규식은 알아두면 유용할 것 같다.

SQL(MySQL)

입양 시각 구하기

문제 및 테이블 예시

  • ANIMAL_OUTS 테이블에서 09:00 부터 19:59까지 각 시간대 별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성
  • 결과는 시간대 순으로 정렬해야 함

입출력 예시

나의 풀이

SELECT
    DATE_FORMAT(DATETIME, "%H") AS HOUR,
    COUNT (ANIMAL_ID) AS COUNT
FROM ANIMAL_OUTS
WHERE
    HOUR(DATETIME) >= 9 AND HOUR(DATETIME) < 20
GROUP BY
    HOUR
ORDER BY
    HOUR
  • DATE_FORMAT()의 입력 순서가 햇갈려서 한번더 검색을 했다. 처음이 컬럼, 두번째가 조회할 포맷이라는 것을 한번더 상기 시켰다
  • 이후 요구 조건에 따라 WHERE절에 HOUR(컬럼)으로 9시00분 부터 20시 미만(19시59분)까지로 작성하고 갯수를 구하기 위해 조회문에서 별칭으로 지정한 HOUR를 기준으로 GROUP BY를 하여 문제를 해결 했다
  • 날짜 타입 걸럼에서 각 시간을 조회하는 HOUR() 함수 외에도 MINUTE(), SECOND()함수도 있다
  • WHERE 절에 함수 없이 조회할 범위의 날짜를 직접 입력해도 되고 BETWEEN 함수를 사용해도 된다.

자동차 종류 별 특정 옵션이 포한된 자동차 수 구하기

문제 및 테이블 예시

  • CAR_RENTAL_COMPANY_CAR 테이블에서 '통풍시트', '열선시트', '가죽시트' 중 하나 이상의 옵션이 포함된 자동차가 종류별로 몇 대 인지 출력하는 SQL문 작성
  • 자동차 수에 대한 컬럼명은 CARS로 지정하고 결과는 자동차 종류를 기준은로 오름차순 정렬

입출력 예시

나의 풀이

SELECT
    CAR_TYPE,
    COUNT(*) AS CARS
FROM
    CAR_RENTAL_COMPANY_CAR
WHERE
    OPTIONS LIKE '%가죽시트%' OR OPTIONS LIKE '%열선시트%' OR OPTIONS LIKE '%통풍시트%'
GROUP BY
    CAR_TYPE
ORDER BY
    CAR_TYPE
  • 한 컬럼에 여러 조건을 검색하기 위해서 LIKE와 OR 키워드를 사용하여 해당 문자가 포함되어있는지 확인하도록 쿼리를 작성하였음
  • 다른 풀이를 찾아보니 WHERE 에서 '시트'관련된 옵션만 찾기 때문에 '%시트%' 로 검색해도 동일한 결과가 나오기 때문에 이렇게 조금더 간단하지만 명확하게 조건문을 작성하는 생각을 한번더 필요해 보임
728x90