Java - 알고리즘

백준 Java - 4단계 1차원 배열 활용하기(3) : 8958번, 4344번

TerianP 2021. 10. 25.
728x90

오늘도 백준 자바 알고리즘 2문제를 완료하였습니다.

8958번, 4344번 바로 시작하겠습니다!!

 

1. 8958번 : OX 퀴즈 문제!

OXXXOXXX 와 같이 주어지는 퀴즈가 있다. O 는 문제를 맞은거고 X 는 문제를 틀린것이라고 한다.

이때 문제를 맞은 경우 그 문제의 점수는 그 문제까지의 연속된 O 의 갯수이다. 예를 들어 "OOXXOXXOOO"의 점수는 1+2+0+0+1+0+0+1+2+3 = 10점이라고 합니다. 이때 OX 퀴즈 결과가 주어졌을때 점수를 구하는 코드를 작성해야한다.

	static void Q_8958() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));


		int result = 0; // OX 갯수
		int score = 0; // 최종 OX 갯수
		int num = Integer.parseInt(br.readLine()); // OX 입력받기
		String[] arr = new String[num]; 
		char[] tmp; // 배열 인덱스의 값을 char 배열로 저장하기 위해 사용



		for(int i=0; i<num; i++) {
			arr[i] = br.readLine();
		}

//		bw.write(Arrays.toString(arr));

		for(int j=0; j<arr.length; j++) {
			// 반복문 돌때마다 초기화
			score = 0;  // 점수
			result = 0; // 최종 점수
			
			tmp = arr[j].toCharArray(); // 각 배열에 있는 OX를 tmp 배열에 char 타입으로 생성
//			System.out.println(Arrays.toString(tmp));
			
			for(int k=0; k<tmp.length; k++) {
				if(tmp[k]=='O') { // 배열의 인덱스가 O 면
//					score+=1; // result+1
//					result+=score; // score 를 result 에 저장
					result+=(score+=1);
				}else { // 만약 중간에 X 가 있으면
					score = 0; // score 값 초기화
				}
			}
			bw.write(result+"\n"); // arr 배열의 인덱스를 한번 꺼내서 돌때마다 출력
			bw.flush();
		}


		br.close();
		bw.flush();
		bw.close();

	}
  • 이 문제에서 가장 주의해야 할 점은 O 가 연속될때까지의 점수가 합쳐진다는 점과 중간에 X가 오는 순간 점수가 다시 0으로 초기화 된다는 점이다. 이 부분만 주의하면서 문제를 풀면 편하게 풀 수 있다고 생각한다.

1) for문을 통한 score 와 result 증가 & 초기화

		for(int j=0; j<arr.length; j++) {
			// 반복문 돌때마다 초기화
			score = 0;  // 점수
			result = 0; // 최종 점수
			
			tmp = arr[j].toCharArray(); // 각 배열에 있는 OX를 tmp 배열에 char 타입으로 생성
//			System.out.println(Arrays.toString(tmp));
			
			for(int k=0; k<tmp.length; k++) {
				if(tmp[k]=='O') { // 배열의 인덱스가 O 면
//					score+=1; // result+1
//					result+=score; // score 를 result 에 저장
					result+=(score+=1);
				}else { // 만약 중간에 X 가 있으면
					score = 0; // score 값 초기화
				}
			}
			bw.write(result+"\n"); // arr 배열의 인덱스를 한번 꺼내서 돌때마다 출력
			bw.flush();
		}

① char 배열 타입의 tmp 를 확인하자. 해당 코드를 보면 arr[j] 를 꺼내와서 char 타입으로 변환 후 tmp 에 저장한다. 즉 첫번째 입력했던 OX 퀴즈의 내용이 OXXOXOX 였다면 이를 char 타입으로 쪼개서 tmp = [O, X, X, O, X, O, X] 와 같이 저장한다. 이때문에 안쪽 for 문은 tmp.length(tmp 의 길이만큼) 반복하게 된다.

 

요렇게 char 배열로 저장된다

② 이후에는 사실 쉽게 할 수 있다. for 문을 한번 더 사용해서 tmp 인덱스의 값이 O 면 score에 1씩 더한다. 그리고 해당 값을 result 에 저장해둔다.

③ 만약 X 라면(O 가 아니라면) score 를 0 으로 초기화하고 다시 다음 tmp 의 k 번째 부터 OX 여부를 확인한다.

④ 최종적으로 tmp 배열의 끝까지 검사가 완료되면, result 값을 출력하고, 다음 arr 인덱스의 OX 퀴즈 결과를 불러와 tmp 배열에 저장 후 result 와 score 는 0 으로 초기화한다.

⑤ 이후 arr 배열에 저장되어 있는 퀴즈의 결과만큼 1 ~ 4까지 반복한다.

 

2. 4344번 : 평균은 넘겠지!

대학생 새내기들의 90%는 자신이 반에서 평균은 넘는다고 생각한다. 당신은 그들에게 슬픈 진실을 알려줘야 한다ㅠㅠ

 

이거 문제를 보니까 제 대학교때가 떠오르네요ㅋㅋ저는 2년제를 졸업 후 4년제로 편입을 했습니다. 중간에 편입했을때 학점이 나름 그래도 괜찮았던지라 편입한 학교에서도 상위권에 멋지게 안착 할 것이라고 생각하면서 첫 중간고사를 보았습니다. 당시 시험 과목이 '사회복지 정책론' 이었는데 세상에 시험 결과가 정말이지, 난생 처음받아보는 점수였던게 기억에 남습니다ㅋㅋㅋㅋ동시에 편입한 동기들도 다 같이 멘붕...ㅋㅋ

당시 해당 시험에서 딱 1문제만 틀린 선배가 있었는데 그 분이 교수님께 선물(성적이 좋으면 교수님께서 선물을 주시곤 했습니다)을 받는 모습을 보면서 '저 사람은 뭐하는 사람이지...?' 라면서 동기들과 이야기했던 기억이 납니다ㅋㅋ후에 알고보니 그 분이 과탑이란 걸 알고나서야 이해가 되더랍니다ㅋㅋ

 

잡설은 이만하고, 코드 확인하겠습니다!

	static void Q_4344() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

		int t_case = Integer.parseInt(br.readLine()); // 테스트 케이스
		String[] score = new String[t_case]; // 입력받은 점수
		String[] arr = null; // score 각 인덱스의 내용을 배열로 받아옴
				
		for(int i=0; i<score.length; i++) {
			score[i] = br.readLine();
		}
		
		for(int j=0; j<score.length; j++) {
			arr = score[j].split(" ");
			
			int max = 0; // 최댓값
			float avag=0; // 현재 평균
			float result=0; // 평균치를 넘는 점수 비율
			int count=0; // 평균보다 높은 점수 갯수
			
			for(int k=1; k<arr.length; k++) {
				avag+=Integer.parseInt(arr[k]);
				
				if(Integer.parseInt(arr[k])>max) {
					max = Integer.parseInt(arr[k]); // 최댓값 계산
				}				
			}
			
			avag = (float)avag/Integer.parseInt(arr[0]); // 평균계산
			
			for(int n=1; n<arr.length; n++) {
			
				if(Integer.parseInt(arr[n])>avag) { // 평균이상인 값이 있을때마다 count+1
					count+=1;
				}
				
				result = ((float)count/Integer.parseInt(arr[0]))*100; // (평균 이상인 값의 수/전체 점수 갯수)*100
			}
//			System.out.println("########" +j+"번째 #########");
//			System.out.println("avag = "+avag);
//			System.out.println("max = "+max);
//			System.out.println("count = "+count);
//			System.out.printf("result = %.3f%% \n",result);
//			System.out.println("######################");
			System.out.printf("%.3f%% \n",result);
		}

		br.close();
		bw.flush();
		bw.close();
		
	}

 

  • 이 문제는 입력받는 수 중 전체 케이스와 세부 케이스(과목 점수의 갯수), 점수에 대해서 모두 생각해야하고 그것들을 나누어서 연산을 해야했기 때문이다. 때문에 실제 코드에서도 전체 테스트 케이스(t_case), 입력받는 점수 배열(score), score 배열의 인덱스 값을 다시 하나의 배열로 짜기 위한 arr(기능상 바로 위 문제의 tmp 배열과 동일하다) 로 나누어 생각했다.
  • 이때 중요한 것은 2번째 줄부터 입력받는 숫자 중 첫번째 숫자는 '앞으로 입력받을 점수의 갯수' 이다. 문제로 생각하자면 입력받을 점수 과목의 갯수!!

1) 변수 초기화

int t_case = Integer.parseInt(br.readLine()); // 테스트 케이스
String[] score = new String[t_case]; // 입력받은 점수
String[] arr = null; // score 각 인덱스의 내용을 배열로 받아옴

아래 변수들은 for 문 안에서 선언해도 무방함
int max = 0; // 최댓값
float avag=0; // 현재 평균
float result=0; // 평균치를 넘는 점수 비율
int count=0; // 평균보다 높은 점수 갯수

 

2) 이중 for 문을 활용하여 최댓값, 평균, 평균 이상인 점수의 비율 구하기

① 먼저 score 배열에 인덱스 첫번째 값을 꺼내서 arr 배열에 저장한다.

② 다음으로 arr 배열의 두번째 값(인덱스 1)부터 꺼내서 avag 에 저장한다. 첫번째 값이 아닌 두번째부터 저장하는 이유는 arr 배열의 첫번째값은 전체 과목의 갯수이지 점수 자체가 아니기 때문이다.

③ 이후 avag 를 arr 배열의 첫번째 값(인덱스 0)으로 나눈다. 이는 평균을 구하는 공식이 전체 점수의 합 / 전체 과목 갯수 이기 때문이다. 동시에 해당 반복문을 통해 최댓값을 계산하여 max 에 저장한다.

		for(int j=0; j<score.length; j++) {
			arr = score[j].split(" ");
			
			int max = 0; // 최댓값
			float avag=0; // 현재 평균
			float result=0; // 평균치를 넘는 점수 비율
			int count=0; // 평균보다 높은 점수 갯수
			
			for(int k=1; k<arr.length; k++) {
				avag+=Integer.parseInt(arr[k]);
				
				if(Integer.parseInt(arr[k])>max) {
					max = Integer.parseInt(arr[k]); // 최댓값 계산
				}				
			}
			
			avag = (float)avag/Integer.parseInt(arr[0]); // 평균계산

④ 두번째 for 문과 if 문을 활용하여 평균보다 큰 값이 몇개가 있는지 계산한다. 이때 for 문은 arr 배열 두번째 인덱스부터 끝까지 반복하고, 평균(avag)보다 큰 값이 있을때마다 count 에 +1을 한다. 

			for(int n=1; n<arr.length; n++) {
			
				if(Integer.parseInt(arr[n])>avag) { // 평균이상인 값이 있을때마다 count+1
					count+=1;
				}
				
				result = ((float)count/Integer.parseInt(arr[0]))*100; // (평균 이상인 값의 수/전체 점수 갯수)*100
			}
		}

⑤ count 를 계산한 후 평균보다 큰 값의 비율을 계산한다. 계산법은 (평균 이상인 값의 수) / (전체 점수의 갯수) * 100

이때 소숫점을 계산해야하기 때문에 float 타입으로 형변환 하는 것을 잊지 말아야한다.

⑥ 이제 result 값을 출력한다. 출력형식은 printf 를 사용하였으며, 소숫점 3번째 자리까지 계산해야하기 때문에 %.3f 형태를 취하였다. %% 처럼 %를 두번 사용한 이유는 한번만 사용하면 그냥 일반적은 % 로 인식하기 때문에 계산 부호인 %를 출력하기 위해서 % 를 두번 사용하였다.

=> 다른 println 문은 그때그때 출력이 잘 되는지 디버깅용으로 넣어둔 것이다.

//			System.out.println("########" +j+"번째 #########");
//			System.out.println("avag = "+avag);
//			System.out.println("max = "+max);
//			System.out.println("count = "+count);
//			System.out.printf("result = %.3f%% \n",result);
//			System.out.println("######################");
			System.out.printf("%.3f%% \n",result);

⑦ 이제 1 ~ 6 까지를 score 배열만큼, 즉 테스트 케이스 만큼 반복하게 된다.

 

이번 문제들도 어려운 문제가 많았다. 무엇보다 내가 혼자서 코드를 짤때는 그냥 이렇게되지...하고 넘어갔는데 이걸 직접 글로 풀어가면서 설명하니까 확실히 어렵다는 생각이 많이든다. 앞으로도 더욱 열심히 작성해보겠습니다!

댓글