BAEKJOON - challenge

★★★ BAEKJOON - 5622 : 다이얼

Jelly-fish 2023. 9. 18. 01:08

 

 

프로그램 설계 과정에서 작성한 주석이 포함되어 있는 프로그램 source
import java.util.Scanner;

public class Mytest10
{
	public static void main(String[] args)
	{
		
		// 2 → ABC  : 3sec
		// 3 → DEF  : 4sec
		// 4 → GHI  : 5sec
		// 5 → JKL  : 6sec
		// 6 → MNO  : 7sec
		// 7 → PQRS : 8sec
		// 8 → TUV  : 9sec
		// 9 → WXYZ : 10sec
		
		// 65 66 67      : 3
		// 68 69 70      : 4
		// 71 72 73      : 5
		// 74 75 76      : 6
		// 77 78 79      : 7
		// 80 81 82 83   : 8
		// 84 85 86      : 9
		// 87 88 89 90   : 10
		
		// 위의 표에서 65를 뺀 결과.
		// ↓
		
		// 0     1     2
		// 3     4     5
		// 6     7     8
		// 9    10    11
		// 12   13    14
		// 15   16    17   18
		// 19   20    21
		// 22   23    24   25
		
		
		// 『 위의 표를 2차원 배열로 생성하려면... 』〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
		// ① 8 행, 미지정 열의 2차원 배열 생성.
		// ② 0 번째 행부터 ~ 7 번쨰 행까지 다음을 반복.
		//    ⓐ j ≠ 5, j ≠ 7 이면 : 새로운 3열의 1차원 배열을 생성하여 j번째 행에 저장.
		//    ⓑ j = 5, j = 7 이면 : 새로운 4열의 1차원 배열을 생성하여 j번째 행에 저장.
		// 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
		
		// 1. 변수 선언
		
		Scanner sc = new Scanner(System.in);
		String inputStr; //--> 입력받은 문자열을 저장할 변수.
		char[] chArr;    //--> 입력받은 문자열을 substring() 메소드로 하나 씩 쪼개어,
		                 //    char 형태로 형변환 한 후 요소로 저장할 문자 배열.

		int secSum = 0;
		int[] jIndex;
		
		int[] timeTakenArr = {3, 4, 5, 6, 7, 8, 9, 10}; //--> 입력받은 알파벳 대문자를 다이얼에 걸 때
		                                                //    필요한 초를 나열해 놓은 배열.
		int[] intArr;


		// ① 8 행, 미지정 열의 2차원 배열 생성.
		int[][] dialArr = new int[8][];
		
		// 1씩 증가시키면서, 배열의 빈 방들을 채워 줄 4Byte 정수형 변수 n.
		int n = 0;
		

		for(int j = 0; j < 8; j++)
		{
			// j = 5, j = 7이면, 열은 4개로 설정.
			if (j == 5 || j == 7)
			{
				dialArr[j] = new int[4];
				
				for(int i = 0; i < 4; i++)
				{
					dialArr[j][i] = n;
					n++;
				}
			}
			

			// j ≠ 5, j ≠ 7일 경우, 열은 3개로 설정.
			else 
			{
				dialArr[j] = new int[3];
				
				
				for(int i = 0; i < 3; i++)
				{
					dialArr[j][i] = n;
					n++;
				}
				
			}
		
		}
		//  ↑ 여기까지 하면
		/*========『 dial의 (대문자 알파벳 - 65) 일 때의 표 』를 배열로 구성 완료. ]==============
				
				0  1  2
			  	3  4  5
			  	6  7  8
			  	9 10 11
			 	12 13 14
			 	15 16 17 18		--> 계단식 배열을 사용.
			 	19 20 21
			 	22 23 24 25     --> 계단식 배열을 사용.
		==================================================================================
		*/
		
		// 이제, 배열 구성을 완료했으므로...거의 다 한 거나 다름없다.
		// ****************************
		// j = 0 이면, 다이얼의 초는 3초.
		// j = 1 이면, 다이얼의 초는 4초.
		// j = 2 이면, 다이얼의 초는 5초.
		// j = 3 이면, 다이얼의 초는 6초.
		// j = 4 이면, 다이얼의 초는 7초.
		// j = 5 이면, 다이얼의 초는 8초.
		// j = 6 이면, 다이얼의 초는 9초.
		// j = 7 이면, 다이얼의 초는 10초.
		// *****************************
		
		// 즉, ① 입력 받은 알파벳 대문자의 ASCII CODE 값에서 65를 빼고...
		
		// ② for 문을 돌면서
		//  [ j = 0 ~ 7 ]───────────────────────────────┐ 
		//  │             j ≠ 5, j ≠ 7 : (i = 0 ~ 2)    │
		//  │             j = 5, j = 7 : (i = 0 ~ 3)    │
		//  └───────────────────────────────────────────┘

		// ③ 일치하는 값을 발견하면, j의 인덱스 값을 반환하도록 하여
		
		// ④ j의 인덱스 값 → 걸리는 sec(초)의 배열 timeTakenArr = {3, 4, 5, 6, 7, 8, 9, 10} 과 매치하여
		
		// ⑤ 총 값을 더해서 출력하면 된다.
		
		
		
		// 2. 문자열을 입력 받는다.
		//    그리고, 그 문자열의 각각을 쪼개 문자열 배열에 저장한 후, 
		
		// 만약, 문자열 길이 3 이면...
		//┌───────┬─────────┐
		//│   i   │  i + 1  │
		//├───────┼─────────┤   →  i 는 『 0 부터 ~ (문자열 길이 - 1) 』 까지 반복
		//│   0   │    1    │   →  i = 0 ; i < inputStr.length(); i++
		//│   1   │    2    │  
		//│   2   │    3    │  
		//└───────┴─────────┘ 
		
		inputStr = sc.next();
		// replaceAll(String regex, String replacement) : 패턴(정규식)이 일치할 경우 모두 대치하는 메소드.
		// \\p{Z} : 모든 구분 기호(Separator) Z 를 → ""(아무것도 작성되지 않은 것) 으로 변경.
		inputStr = inputStr.replaceAll("\\p{Z}", ""); // 문자열의 모든 공백 제거 정규식.
		
		// 입력된 문자열의 공백을 제거 후, intArr의 길이를 지정.
		 intArr = new int[inputStr.length()];
		 jIndex = new int[intArr.length];
		
		// intArr의 빈 방에, 문자열을 각각의 문자로 쪼갠 뒤(charAt) int 타입으로 변환.
		// (문자열 타입은 정수 타입으로 변환할 수 없으므로.)
		// 그 이후에, 65를 뺀다. (다이얼 배열의 값과 일치하도록 하기 위해)
		
		for(int i = 0; i < inputStr.length(); i++)
		{
			intArr[i]= ((int)inputStr.charAt(i) - 65); 
		}
		

		// ① 입력 받은 알파벳 대문자의 ASCII CODE 값에서 65를 빼고...
		
		// ② for 문을 돌면서
		//  [ j = 0 ~ 7 ]───────────────────────────────┐ 
		//  │             j ≠ 5, j ≠ 7 : (i = 0 ~ 2)    │
		//  │             j = 5, j = 7 : (i = 0 ~ 3)    │
		//  └───────────────────────────────────────────┘

		// ③ dialArr 의 요소 값과 intArr 의 요소 값이 일치하면, j의 인덱스 값을 반환하도록 하여
		
		// ④ j의 인덱스 값 → 걸리는 sec(초)의 배열 timeTakenArr = {3, 4, 5, 6, 7, 8, 9, 10} 과 매치하여
		//  j = 0 → 3초  (timeTakenArr[0])
		//  j = 1 → 4초  (timeTakenArr[1])
		//  j = 2 → 5초  (timeTakenArr[2])
		//  j = 3 → 6초  (timeTakenArr[3])
		//  j = 4 → 7초  (timeTakenArr[4])
		//  j = 5 → 8초  (timeTakenArr[5])
		//  j = 6 → 9초  (timeTakenArr[6])
		//  j = 7 → 10초 (timeTakenArr[7])

		// ☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★
		// 즉, 다이얼을 돌리는 데 걸리는 총 시간 secSum은...
		// 『secSum += timeTaken[j]』 이다.
		// ☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★

		// ⑤ 이제, secSum에 timeTaken[j]의 값을 누적합 하여 출력하면 된다.
		
		
		
		for (int j = 0; j < 8; j++)
		{
			
			if (j == 5 || j == 7)
			{
				for (int i = 0; i < 4; i++)
				{

					for (int s = 0; s < intArr.length; s++)
					{
						if (dialArr[j][i] == intArr[s])
						{
						
							//System.out.println("[일치]  dialArr[" + j + "]" + "[" + i + "]" +  dialArr[j][i]);
							//System.out.println("[일치] intArr[" + s + "]" + intArr[s]);
							
							// 다이얼을 돌리는 데 걸리는 총 시간 secSum은...
							// 『secSum += timeTaken[j]』 이다.
							System.out.println("입력한 문자 : " + (char)(intArr[s]+65));
							System.out.println("다이얼을 돌리는데 필요한 시간 : " + timeTakenArr[j]);
							secSum += timeTakenArr[j];
							
						}
					}
					

					
					
					
				}
				
			}
			
			else
			{
				
				for (int i = 0; i < 3; i ++)	
				{
					for (int s = 0; s < intArr.length; s++)
					{
						if (dialArr[j][i] == intArr[s])
						{
							//System.out.println("[일치]  dialArr[" + j + "]" + "[" + i + "]" +  dialArr[j][i]);
							//System.out.println("[일치] intArr[" + s + "]" + intArr[s]);
							System.out.println("입력한 문자 : " + (char)(intArr[s]+65));
							System.out.println("다이얼을 돌리는데 필요한 시간 : " + timeTakenArr[j]);
							
							secSum += timeTakenArr[j];

						}
					}
					

				
				}

			}

		}
		
		
		for (int i = 0; i < inputStr.length(); i++)
		{
			System.out.print(intArr[i] + " ");
		}
		System.out.println();
		
		System.out.println("다이얼을 돌리는데 총 필요한 시간 : " + secSum);
		
		
	}
}

 

주석을 모두 제거하고, 실제 백준에 제출한 프로그램
import java.util.Scanner;

public class Main
{
	public static void main(String[] args)
	{
		
		Scanner sc = new Scanner(System.in);
		String inputStr; //--> 입력받은 문자열을 저장할 변수.
		char[] chArr;    //--> 입력받은 문자열을 substring() 메소드로 하나 씩 쪼개어,
		                 //    char 형태로 형변환 한 후 요소로 저장할 문자 배열.

		int secSum = 0;
		int[] jIndex;
		
		int[] timeTakenArr = {3, 4, 5, 6, 7, 8, 9, 10}; //--> 입력받은 알파벳 대문자를 다이얼에 걸 때
		                                                //    필요한 초를 나열해 놓은 배열.
		int[] intArr;


		// ① 8 행, 미지정 열의 2차원 배열 생성.
		int[][] dialArr = new int[8][];
		
		// 1씩 증가시키면서, 배열의 빈 방들을 채워 줄 4Byte 정수형 변수 n.
		int n = 0;
		

		for(int j = 0; j < 8; j++)
		{
			// j = 5, j = 7이면, 열은 4개로 설정.
			if (j == 5 || j == 7)
			{
				dialArr[j] = new int[4];
				
				for(int i = 0; i < 4; i++)
				{
					dialArr[j][i] = n;
					n++;
				}
			}
			

			// j ≠ 5, j ≠ 7일 경우, 열은 3개로 설정.
			else 
			{
				dialArr[j] = new int[3];
				
				
				for(int i = 0; i < 3; i++)
				{
					dialArr[j][i] = n;
					n++;
				}
				
			}
		
		}
		
		
		inputStr = sc.next();
		// replaceAll(String regex, String replacement) : 패턴(정규식)이 일치할 경우 모두 대치하는 메소드.
		// \\p{Z} : 모든 구분 기호(Separator) Z 를 → ""(아무것도 작성되지 않은 것) 으로 변경.
		inputStr = inputStr.replaceAll("\\p{Z}", ""); // 문자열의 모든 공백 제거 정규식.
		
		// 입력된 문자열의 공백을 제거 후, intArr의 길이를 지정.
		 intArr = new int[inputStr.length()];
		 jIndex = new int[intArr.length];
		
		
		for(int i = 0; i < inputStr.length(); i++)
		{
			intArr[i]= ((int)inputStr.charAt(i) - 65); 
		}
		

		
		for (int j = 0; j < 8; j++)
		{
			
			if (j == 5 || j == 7)
			{
				for (int i = 0; i < 4; i++)
				{

					for (int s = 0; s < intArr.length; s++)
					{
						if (dialArr[j][i] == intArr[s])
						{
						
							secSum += timeTakenArr[j];
							
						}
					}

					
				}
				
			}
			
			else
			{
				
				for (int i = 0; i < 3; i ++)	
				{
					for (int s = 0; s < intArr.length; s++)
					{
						if (dialArr[j][i] == intArr[s])
						{
							
							secSum += timeTakenArr[j];

						}
					}
					

				
				}

			}

		}
		
	
		System.out.println(secSum);

	}
}

 

제출해서 정답을 맞히긴 했지만, 걸리는 점이 많은 프로그램이다.

 

switch 문으로 처리하는 방식이 가장 먼저 떠올랐지만... 그 방식 말고,  2차원 배열을 이용해서  풀어보고 싶어서

계단식 배열을 사용했는데...(PQRS, WXYZ 때문에 계단식 배열.)

 

처리하는 과정에서 for문의 회전 수가 너무 많아지고...(배열 값과 일치하는지를 한번씩 계속 돌면서 확인해보기 때문에...)

BufferedReader가 아닌, Scanner를 써버려서 처리 시간이 길게 걸린 것 같다... (204ms)

for문과 if문을 중첩해 놓으니 프로그램의 가독성도 좋지 않다. (차라리 간단하게 switch를 쓰는 방법이 더 처리 시간도 적고 보기 간편했을 듯...🤯🥺😭)

 

소스가 너무... 유인원 같아서... 반복문을 사용하는 방법 중에서 프로그램 길이를  줄일 수 있는 방법을 알게 되면 나중에 꼭 손 봐보고 싶다...😰

 

 

챗 GPT가 작성한 이 문제의 해결 프로그램 [1]  -  매우 간단하고, 백준에 제출했을 때도 정답이다...
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // 입력을 받기 위한 Scanner 객체를 생성합니다.
        Scanner scanner = new Scanner(System.in);

        // 입력 문자열을 받고 양쪽의 공백을 제거하여 처리합니다.
        String word = scanner.nextLine().trim();

        // Scanner를 닫습니다.
        scanner.close();

        // 전체 걸리는 시간을 저장할 변수를 초기화합니다.
        int total_time = 0;

        // 입력 문자열을 문자로 분해하고 각 문자에 대해 처리합니다.
        for (char c : word.toCharArray()) {
            // getDialNumber 함수를 호출하여 해당 문자에 대응하는 다이얼 숫자를 가져옵니다.
            int dialNumber = getDialNumber(c);

            // 각 숫자를 누르는데 필요한 시간은 숫자 + 1입니다.
            // 예를 들어, 2를 누르는데는 3초가 필요하므로 2 + 1 = 3이 됩니다.
            total_time += dialNumber + 1;
        }

        // 총 시간을 출력합니다.
        System.out.println(total_time);
    }

    // 알파벳 대문자에 대응하는 다이얼 숫자를 반환하는 메서드입니다.
    public static int getDialNumber(char c) {
        // 각 알파벳에 대응하는 다이얼 숫자를 문자열로 나타낸 것에서 해당 문자의 아스키 코드를 사용하여 가져옵니다.
        // 예를 들어, 'A'의 아스키 코드는 65이고, '2'를 나타내려면 2를 더하면 됩니다.
        // 따라서 '22233344455566677778889999' 문자열에서 해당 문자의 아스키 코드 값을 사용하여 다이얼 숫자를 가져옵니다.
        return "22233344455566677778889999".charAt(c - 'A') - '0';
    }
}

 


 

챗 GPT가 작성한 이 문제의 해결 프로그램 [2] - 코드가 어려워서 더 쉬운 코드를 부탁해봤다...
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word = scanner.nextLine().trim();
        scanner.close();

        int total_time = 0;
        for (char c : word.toCharArray()) {
            total_time += 2 + (c - 'A') / 3; // 각 알파벳에 해당하는 다이얼 숫자를 계산
            if (c >= 'P' && c <= 'S') total_time++; // 예외 처리
            if (c >= 'T' && c <= 'V') total_time++;
            if (c >= 'W' && c <= 'Z') total_time++;
        }

        System.out.println(total_time);
    }
}
  1. Scanner 객체를 생성하여 표준 입력에서 입력을 받습니다.
  2. 입력 문자열을 trim() 메서드를 사용하여 양쪽 공백을 제거하고 word 변수에 저장합니다.
  3. 총 걸리는 시간을 저장할 total_time 변수를 초기화합니다.

이제 문자열을 순회하면서 각 알파벳에 대응하는 다이얼 숫자를 계산하고, 예외 처리를 적용합니다.

  1. for-each 루프를 사용하여 word 문자열을 문자로 분해합니다.
  2. 각 문자에 대해 다이얼 숫자를 계산합니다. (c - 'A') / 3을 통해 각 알파벳에 해당하는 다이얼 숫자를 구합니다. 'A'에서 'C'까지는 2, 'D'에서 'F'까지는 3, 'G'에서 'I'까지는 4, ..., 'W'에서 'Z'까지는 9입니다.
  3. 몇몇 알파벳은 예외 처리를 해야 합니다. 'P', 'Q', 'R', 'S'는 7로 계산해야 하므로, 해당 조건에 만족할 경우 total_time에 1을 추가합니다. 'T', 'U', 'V'는 8로 계산해야 하므로, 해당 조건에 만족할 경우도 1을 추가합니다. 마찬가지로 'W', 'X', 'Y', 'Z'는 9로 계산하므로, 해당 조건에 만족할 경우도 1을 추가합니다.
  4. 마지막으로 total_time을 출력하여 총 걸리는 시간을 표시합니다.

이 코드는 입력 문자열을 처리하고 각 알파벳에 대응하는 다이얼 숫자를 계산하는 과정을 더 간단하게 표현하였습니다. 각 알파벳에 대응하는 다이얼 숫자를 계산하는 수식 (c - 'A') / 3을 사용하여 간단하게 처리하였으며, 예외 처리도 간단하게 구현하였습니다.

 

챗 GPT가 작성한 프로그램 분석하고... 내가 몰랐던 메소드, 간단하게 처리할 수 있는 로직 얻어갈 수 있도록 하자...😞💦😢💧