👨‍💻 Coding Test/Programers

[Programmers/Java/Lv.1/조합] 36.소수 만들기

Developer Quarterly 2025. 5. 14. 17:34

문제 설명

주어진 숫자 중 3개의 수를 더했을 때 소수가 되는 경우의 개수를 구하려고 합니다. 숫자들이 들어있는 배열 nums가 매개변수로 주어질 때, nums에 있는 숫자들 중 서로 다른 3개를 골라 더했을 때 소수가 되는 경우의 개수를 return 하도록 solution 함수를 완성해주세요.

 

제한사항

  • nums에 들어있는 숫자의 개수는 3개 이상 50개 이하입니다.
  • nums의 각 원소는 1 이상 1,000 이하의 자연수이며, 중복된 숫자가 들어있지 않습니다.

 

입출력 예

nums result
[1,2,3,4] 1
[1,2,7,6,4] 4

입출력 예 #1 : 
[1,2,4]를 이용해서 7을 만들 수 있습니다.

입출력 예 #2 : 
[1,2,4]를 이용해서 7을 만들 수 있습니다.
[1,4,6]을 이용해서 11을 만들 수 있습니다.
[2,4,7]을 이용해서 13을 만들 수 있습니다.
[4,6,7]을 이용해서 17을 만들 수 있습니다.

 

for문 풀이

class Solution {
    public int solution(int[] nums) {
        int count = 0;

        int n = nums.length;
        for (int i = 0; i < n - 2; i++) {
            for (int j = i + 1; j < n - 1; j++) {
                for (int k = j + 1; k < n; k++) {
                    int sum = nums[i] + nums[j] + nums[k];
                    if (isPrime(sum)) {
                        count++;
                    }
                }
            }
        }

        return count;
    }

    // 소수 판별 함수
    private boolean isPrime(int num) {
        if (num < 2) {
            return false;
        }
        
        for (int i = 2; i * i <= num; i++) { // √num 까지만 검사
            if (num % i == 0) {
                return false;
            }
        }
        
        return true;
    }
}

isPrime 함수에서 i * i <= num만 즉, num의 제곱근까지만 검사하는 이유는?

안쪽부터 두 개씩 짝지어지는것처럼 소수가 아닌 어떤 수(합성수)는 두 자연수의 곱으로 표현할 수 있기 때문이다.
예를 들어 num = 36이라고 하면 36의 약수는 1, 2, 3, 4, 6, 9, 12, 18, 36
여기서 6 이하인 약수로 모두 36 = a × b 형태로 만들 수 있다.
즉, 6보다 큰 약수는 짝으로 맞춰져서 이미 다 나왔기 때문에 굳이 6보다 큰 수들은 직접 검사할 필요가 없다.

소수인 경우 또한 마찬가지다.
예를 들어 num = 29 (소수)일 때 
√29 ≈ 5.38
1, 2, 3, 4, 5까지만 검사하면 된다. 굳이 6,7,8,...29까지 나눠볼 필요 없다.
즉 2, 3, 5 모두 나누어떨어지지 않기 때문에 → 29는 소수임을 판별할 수 있다.

 

DFS 풀이

class Solution {
    int answer = 0; // 최종 소수 조합 개수 저장

    public int solution(int[] nums) {
        // 초기: nums 배열 중에서 3개 고르는 DFS 시작
        dfs(nums, 0, 0, 0);
        return answer;
    }

    // dfs: 배열, 현재 시작 인덱스, 고른 개수, 고른 숫자의 합
    private void dfs(int[] nums, int start, int count, int sum) {
        if (count == 3) { // 3개를 고르면
            if (isPrime(sum)) {
                answer++;
            }
            return;
        }

        // 현재 인덱스부터 끝까지 반복 (앞에 고른 숫자 다음부터만 선택)
        for (int i = start; i < nums.length; i++) {
            dfs(nums, i + 1, count + 1, sum + nums[i]);
        }
    }

    // 소수 판별 메서드
    private boolean isPrime(int num) {
        if (num < 2) return false;
        for (int i = 2; i * i <= num; i++) {
            if (num % i == 0) return false;
        }
        return true;
    }
}