완전탐색

배지원·2022년 11월 1일
0

알고리즘

목록 보기
9/16

프로그래머스
https://school.programmers.co.kr/learn/courses/30/lessons/42840

1. 문제

완전탐색(모의고사)

  • 3명이 모의고사를 푸는데 1번부터 마지막 문제까지 다음과 같이 반복하여 찍는다.

1번 사람 : 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, …
2번 사람 : 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, …

3번 사람 : 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, …

1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성하라.


2. 문제 분석

  1. 3명의 답안지를 String혹은 배열을 통해 입력받는다.

  2. 정답지와 답안지를 비교하여 각 답안지마다 맞은 점수를 기록한다.

  3. 가장 많이 문제를 맞힌 사람이 누구인지 찾아내 배열에 담아 출력한다.


🚫 제한조건

  • 시험은 최대 10,000 문제로 구성되어있습니다.
  • 문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
  • 가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.

3. 설계

(1) 답안지 배열로 입력받는 경우

int[] user1 = {1,2,3,4,5};
int[] user2 = {2,1,2,3,2,4,2,5};
int[] user3 = {3,3,1,1,2,2,4,4,5,5};
        
int[] temp = {0,0,0};           // 결과 저장할 배열
  • 각 인원의 답안지를 배열로 저장
  • 채점점수를 기록할 temp배열 생성
for (int i = 0; i < answers.length; i++) {
     if(answers[i] == user1[i%user1.length])
        temp[0]++;
     if(answers[i] == user2[i%user2.length])
        temp[1]++;
     if(answers[i] == user3[i%user3.length])
        temp[2]++;
}
  • 시험문제는 총 10000문제이하로 구성이 되어 있으므로 몇번째 문제가 와도 답안지와 비교를 해야한다.
  • 현재 답안지에는 반복하는 과정이 한 사이클만 작성되어 있으므로 그 이상의 문제가 입력될 시 나머지값을 구하는 방식을 통해 비교할 수 있다.

예) user1 = {1,2,3,4,5} 은 총 5개의 답안지로 반복이 되고 5개의 답만 저장이 되어있다 만약 {1,2,3,4,5,6,7} 총 7문제가 입력이 되어 있다면 7번문제에 해당하는 답안지를 구하기 위해서는 6%5[user1 길이] = 1의 식을 통해 user1의 index 1번째의 값 2와 비교를 하게 된다.

  • 각 인원별 답안지를 비교하여 정답일 경우 정답 수를 저장하는 배열의 값을 +1하여 저장한다.
int max = Math.max(temp[0], Math.max(temp[1],temp[2])); // 3개의 값 중 최대값 저장
        List<Integer> maxScore = new ArrayList<>();
        // 최대값이 중복일 경우 리스트에 추가해줌
        for(int i=0; i<temp.length; i++){
            if(max == temp[i])
                maxScore.add(i+1);
        }
  • 두 인자 값 중 큰 값을 리턴하는 함수인 Math.max( )를 사용하여
    각 인원별 정답수를 비교하여 가장 많이 맞춘 값을 저장한다.
  • 맞춘 정답수가 같을 경우까지 찾아내기위해 가장 큰값을 각 인원별 정답수를 저장한 배열의 모든 값과 비교를하여 같다면 list에 저장한다. ex) max=5이고, temp{5,0,5}일때 temp의 index 0~2까지의 값과 max를 비교하여 index=0, index=2의 값을 list에 저장한다.
// List => Arrays
        int[] result = new int[maxScore.size()];
        for(int i =0; i<maxScore.size(); i++){
            result[i] = maxScore.get(i);
        }
  • 최종적으로 배열을 반환해줘야 하므로 현재 list로 저장되어 있는 값을 배열로 옮겨 준다.

(2) 답안지 문자열로 입력받는 경우

String answerPattern1 = "12345".repeat(2000);
String answerPattern2 = "21232425".repeat(1250);
String answerPattern3 = "3311224455".repeat(1000);
  • 이전과 다르게 이번에는 repeat를 이용하여 미리 10000자리까지 답안지를 채워놓는다.
  • 이때 배열이 아닌 String으로 저장한다.
// 각 사람마다 작성한 답안지를 채점함
// 답이 맞으면 결과 배열의 값을 1씩 증가함
for (int i = 0; i < answers.length; i++) {
   if(Character.getNumericValue(answerPattern1.charAt(i)) == answers[i]) count[0] ++;
   if(Character.getNumericValue(answerPattern2.charAt(i)) == answers[i]) count[1] ++;
   if(Character.getNumericValue(answerPattern3.charAt(i)) == answers[i]) count[2] ++;
}
  • 각 인원의 답안지와 정답을 비교하기 위해 현재 String으로 되어 있는 답안지를 charAt( )을 통해 한자리씩 자르고 Character.getNumbericValue( ) 를 통해 Char ⇒ int 로 바꿔서 비교할 수 있도록 하였다.
  • 만약 같이 같다면 이전처럼 결과를 저장하고 있는 배열의 값을 +1 해주었다.
// 중복 비교
        List<Integer> maxscorelist = new ArrayList<>();
        int maxscore = Math.max(count[0],Math.max(count[1], count[2]));

        for(int i=0; i<count.length; i++){
           if(maxscore == count[i]){           // 최대값이 count배열의 안에 있는 값과 같을시
               maxscorelist.add(i+1);     // list에 i번째의 자리를 넣어야 하는데 배열은 0부터 시작이므로 +1하여 넣는다
           }
        }

// list -> int[]
  int[] result = maxscorelist.stream()
       .mapToInt(Integer::intValue)
       .toArray();

return result;
  • 중복 비교는 이전과 같으므로 생략합니다.
  • list를 배열로 바꿔주는 작업을 이전과 좀 다르게 구현을 해봤다.
int[] arr = list.stream().mapToInt(i -> i).toArray();
  • 정수목록을 정수배열로 변환하는 방법중에 Strem( ).mapToInt( ) 메서드가 있다

(1) Stream목록에서 가져오기

(2) IntStream각 요소를 자체에 매핑하여 각 Integer객체가 보유한 값을 unboxing하여 획득

(3) int 호출하여 배열얻기 toArray


4. CODE

(1) 답안지 배열로 입력받는 경우

public class SearchFull {
    public int[] solution(int[] answers) {
        
        int[] user1 = {1,2,3,4,5};
        int[] user2 = {2,1,2,3,2,4,2,5};
        int[] user3 = {3,3,1,1,2,2,4,4,5,5};

        int[] temp = {0,0,0};

        for (int i = 0; i < answers.length; i++) {
            if(answers[i] == user1[i%user1.length])
                temp[0]++;
            if(answers[i] == user2[i%user2.length])
                temp[1]++;
            if(answers[i] == user3[i%user3.length])
                temp[2]++;
        }

        int max = Math.max(temp[0], Math.max(temp[1],temp[2])); // 3개의 값 중 최대값 저장
        List<Integer> maxScore = new ArrayList<>();
        // 최대값이 중복일 경우 리스트에 추가해줌
        for(int i=0; i<temp.length; i++){
            if(max == temp[i])
                maxScore.add(i+1);
        }

        // List => Arrays
        int[] result = new int[maxScore.size()];
        for(int i =0; i<maxScore.size(); i++){
            result[i] = maxScore.get(i);
        }
        
        return result;
    }

    public static void main(String[] args) {
        SearchFull sf = new SearchFull();

        int[] answers = {1,3,2,4,2,1,4};
        System.out.println(Arrays.toString(sf.solution(answers)));
    }
}

(2) 답안지 문자열로 입력받는 경우

public class SearchFull2 {
    public int[] solution(int[] answers) {
        String answerPattern1 = "12345".repeat(2000);
        String answerPattern2 = "21232425".repeat(1250);
        String answerPattern3 = "3311224455".repeat(1000);

        // 공간복잡도로 속도를 높이는 방법
        int[] count = {0,0,0};

        // 각 사람마다 작성한 답안지를 채점함
        // 답이 맞으면 결과 배열의 값을 1씩 증가함
        for (int i = 0; i < answers.length; i++) {
            if(Character.getNumericValue(answerPattern1.charAt(i)) == answers[i]) count[0] ++;
            if(Character.getNumericValue(answerPattern2.charAt(i)) == answers[i]) count[1] ++;
            if(Character.getNumericValue(answerPattern3.charAt(i)) == answers[i]) count[2] ++;
        }

        // 중복 검사
        List<Integer> maxscorelist = new ArrayList<>();
        int maxscore = Math.max(count[0],Math.max(count[1], count[2]));

        for(int i=0; i<count.length; i++){
           if(maxscore == count[i]){           // 최대값이 count배열의 안에 있는 값과 같을시
               maxscorelist.add(i+1);     // list에 i번째의 자리를 넣어야 하는데 배열은 0부터 시작이므로 +1하여 넣는다
           }
        }
        
        // list -> int[]
        int[] result = maxscorelist.stream()
                .mapToInt(Integer::intValue)
                .toArray();

        return result;
    }
}

(2) TestCase

class SearchFull2Test {

    @Test
    @DisplayName("제일많이 맞춘사람 1명일때")
    void onecheck(){
        SearchFull2 sf = new SearchFull2();

        int[] answers = {1,2,3,4,5};

        assertEquals("[1]",Arrays.toString(sf.solution(answers)));
    }

    @Test
    @DisplayName("제일많이 맞춘사람 1명 이상 일때")
    void twocheck(){
        SearchFull2 sf = new SearchFull2();

        int[] answers2 = {1,3,2,4,2};

        assertEquals("[1, 2, 3]",Arrays.toString(sf.solution(answers2)));
    }
}

5. 결과

시험 답
첫번째 답 : {1,2,3,4,5}
두번째 답 : {1,3,2,4,2}

profile
Web Developer

0개의 댓글