# [완전탐색][Lv2] - 소수찾기 자바스크립트 js

# 프로그래머스 문제

https://programmers.co.kr/learn/courses/30/lessons/42839?language=javascript# (opens new window)

# 시도 1.

  1. getNumbers 함수 : 들어온 문자로 조합 가능한 모든 수를 구한다.

    재귀 함수로 해야겠다는 건 알겠는데 감이 안잡혀서 일단 for문으로 대충 써봤다.

    for(let i=0; i<len; i++){
            numbers[i] 넣음
            for(let j=i; j<len; j++){
                numbers[i]+numbers[j] 넣음
                ... 문자열 길이만큼 반복
            }
        }
    

    이걸 토대로 재귀함수를 만듦.

    parents : string, 앞에서 붙인 문자열. 초기값은 빈값이다.
    nowIdx : 앞에서 붙인 문자열의 idx(idx로 해야 중복 숫자가 들어왔을 때 처리 가능)
    1. 0부터 문자열 끝까지 for문을 돌며 parents+numbers[i] 를 push 한다.
    2. 만약 이미 거쳐간 문자열이라면 push 하지 않는다.
    3. 문자열의 전체 길이와 parents(앞에서 붙인 문자열)의 길이가 다르다면 한번 더 탐색한다.
    

    처음엔 for(let i=parentsLen; i<len; i++) 으로 했더니 1, 7 로 조합할 때 71 이 안나왔다.

    그래서 i=0 으로 수정했더니 이번엔 선택했던 수를 또 선택하여 문제가 생겼다.

    그래서 nowIdx 를 두고, 붙인 숫자의 idx를 담아 같은 수를 선택하지 않도록 했다.

  2. 중복제거, 0과1 빼는 걸 안해서 틀렸었다.

    중복제거는 set으로 했는데 string인 상태로 했더니 001, 01 이런 친구들을 다르게 판단해서

    string array→ int array→ Set → array 의 순서로 바꿔주었다.

function getNumbers(numbersList, numbers, parents='', nowIdx=[]){
    const len = numbers.length;
    const parentsLen = parents.length;
    
    for(let i=0; i<len; i++){
        var _nowIdx = nowIdx.slice();
        if(nowIdx.indexOf(i) === -1){
            numbersList.push(parents+numbers[i]);
            _nowIdx.push(i);
        }
        
        if(nowIdx.indexOf(i) === -1 && parentsLen+1 !== len){
            getNumbers(numbersList, numbers, parents+numbers[i], _nowIdx);
        }
    }
    
    return numbersList
}

function solution(numbers) {
    const len = numbers.length;
    let numbersList = [];
    let answer = 0;
    
    // 조합 되는 모든 수 구하고 숫자 배열로 바꾼 다음 중복 제거
    numbersList = [...new Set(getNumbers(numbersList, numbers).map(v=>+v))];
    
    // 2부터 그 수-1 까지 나눠지지 않으면 소수
    numbersList = numbersList.filter((e) => {
        for(let i=2; i<e; i++){
            if (e%i === 0) return false;
        }
        return true;
    })
    
    answer = numbersList.length;
    
    // 0, 1 제외
    if (numbersList.indexOf(0) !== -1) answer--;
    if (numbersList.indexOf(1) !== -1) answer--;
    
    return answer;
}
정확성  테스트
테스트 1통과 (0.23ms, 30.2MB)
테스트 2통과 (14.97ms, 33.9MB)
테스트 3통과 (0.18ms, 30MB)
테스트 4통과 (6.53ms, 33.7MB)
테스트 5통과 (11.44ms, 35MB)
테스트 6통과 (0.17ms, 30MB)
테스트 7통과 (0.20ms, 29.8MB)
테스트 8통과 (12.75ms, 34.7MB)
테스트 9통과 (0.20ms, 30.1MB)
테스트 10통과 (125.23ms, 33.8MB) <- 이거 시간을 줄이고 싶다
테스트 11통과 (6.68ms, 32.4MB)
테스트 12통과 (0.84ms, 29.9MB)
채점 결과
정확성: 100.0
합계: 100.0 / 100.0

# 다른 사람의 답변/질문에서 효율성 찾기

테스트 10의 시간을 줄일 아이디어가 있을 까 싶어서 통과 한 다음 질문하기와 다른사람의 풀이를 봤다.

  1. 수학을 잘 몰라서요.. 소수인지 판단할땐 i까지 모두 나누지 않아도 된다고 한다. 제곱근 이하까지만 나누어봐도 판단이 가능하다.

    // 2부터 그 수의 제곱근 까지 나눠지지 않으면 소수
    numbersList = numbersList.filter((e) => {
        let sqrt = Math.sqrt(e);
    		// 꼭 <= 이어야 한다. 제곱근'까지'임. = 빼면 테스트 케이스 몇개 통과 못함
        for(let i=2; i<=sqrt; i++){ 
            if (e%i === 0) return false;
        }
        return true;
    })
    
    채점을 시작합니다.
    정확성  테스트
    테스트 1통과 (0.27ms, 30.1MB)
    테스트 2통과 (6.44ms, 33.8MB) <- before (14.97ms, 33.9MB)
    테스트 3통과 (0.13ms, 30.3MB)
    테스트 4통과 (4.83ms, 33.5MB)
    테스트 5통과 (11.79ms, 35MB)
    테스트 6통과 (0.21ms, 30.1MB)
    테스트 7통과 (0.29ms, 30.1MB)
    테스트 8통과 (12.57ms, 34.8MB)
    테스트 9통과 (0.21ms, 30MB)
    테스트 10통과 (5.66ms, 33.7MB) <- before (125.23ms, 33.8MB) 
    테스트 11통과 (0.87ms, 30.1MB) <- before (6.68ms, 32.4MB)
    테스트 12통과 (0.67ms, 29.9MB)
    채점 결과
    정확성: 100.0
    합계: 100.0 / 100.0
    

    완전 많이 줄어들었다!!

Last Updated: 8/11/2022, 5:17:02 AM