Java - 알고리즘

백준 Java - 4단계 1차원 배열 활용하기(2) : 3052번, 1546번

TerianP 2021. 10. 20.
728x90

오늘도 자바 알고리즘 문제 중 3052번 1546번 총 2문제 풀이를 완료했다.

사실 예전처럼 한번에 모아서 싹! 올리고 싶었는데 점점 문제도 뭔가 어려워지고, 코드도 길어져서 이제 풀고 바로바로 올리려고 한다.

 

1. 3052번 : 서로 다른 나머지는 몇 개?

10개의 수를 입력받고 42 로 나누었을 때 서로 다른 나머지값은 몇 개 일까?

import java.io.*;
import java.util.Arrays;

public class Q11_2 {
	public static void main(String[] args) throws IOException {
		Q_3052();
	}
	
	static void Q_3052() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		int[] array = new int[10]; // 10개의 값을 갖는 배열 생성
		int num = 0; // 입력받는 num 값 초기화
		int result = 1; // 나머지는 최소 1개 존재
		
		for(int i=0; i<array.length; i++) { // 배열 끝까지 반복
			num = Integer.parseInt(br.readLine()); // 입력받음
			
			if(0<num && num<1000) { // 입력받는 값은 0 초과 1000 미만
				array[i] = num%42;
			}else {
				break; // 다른값 들어오면 끝!
			}
		}
		
//		bw.write(Arrays.toString(array)+"\n"); // 기존 배열
		Arrays.sort(array); // 배열을 오름차순으로 자동 정렬
//		bw.write(Arrays.toString(array)); // 정렬 후
//		bw.newLine();
//		bw.flush();
		
		// 버블 정렬 사용해서 0번째와 1번째 비교, 1번째와 2번째 비교 ---- 8번째와 9번째까지 비교!
		for(int j=0; j<array.length; j++) { 
			for(int k=j+1; k<array.length; k++) {
				if(array[j]!=array[k]) {
//					bw.write("j 값 : "+j+"\n"); // 몇 번째 배열의 값이 동일하지 않은지 확인하기 위해
//					bw.write("k 값 : "+k+"\n"); // 몇 번째 배열의 값이 동일하지 않은지 확인하기 위해	
//					bw.newLine();
//					bw.flush();
					result+=1; // 다를 경우 result +1
				}
				break; 
			}
		}
		
		bw.write(result+"\n"); // total 출력
		br.close();
		bw.flush();
		bw.close();
	}
  • 이번 문제는 다음 단계를 통해 풀었다. 먼저 기본 변수 생성 -> 숫자 입력 받음 & 입력받은 숫자를 바로 array 배열에 저장 -> arrays.sort 메소드를 사용해 배열을 오름차순으로 정렬! ->  이후 버블정렬 방식으로 0번째와 1번째 비교, 1번째와 2번째와 비교 하면서 끝까지 비교하고 다른 값을 발견할때마다 result+1 실행
  • 요렇게 풀었는데 자세한 내용은 코드를 보면서 작성하도록 하겠다.

1) 기본 변수 생성 & 입력받은 숫자를 바로 array 배열에 저장

  • 여기서 중요한 것은 result 값을 1로 초기화했다는 점이다. 이는 입력받은 숫자를 42로 나누었을 때 나머지가 모두 똑같다고 해도 나머지가 최소 1개는 존재 한다는 점에서 초기값을 1로 두었다.
  • 그 외에는 num 값에 따라서 지정된 값이 안들어오면 반복문을 끝낸다는 정도?
		int[] array = new int[10]; // 10개의 값을 갖는 배열 생성
		int num = 0; // 입력받는 num 값 초기화
		int result = 1; // 나머지는 최소 1개 존재
		
		for(int i=0; i<array.length; i++) { // 배열 끝까지 반복
			num = Integer.parseInt(br.readLine()); // 입력받음
			
			if(0<num && num<1000) { // 입력받는 값은 0 초과 1000 미만
				array[i] = num%42;
			}else {
				break; // 다른값 들어오면 끝!
			}
		}

 

2) arrays.sort 메소드를 사용해 배열을 오름차순으로 정렬!

  • 사실 여기가 가장 중요하다고 생각되는 부분인데 42로 나누었을 때의 나머지는 array 배열에 저장되어 있는 상태이다. 다만 입력받을때 숫자가 오름차순 / 내림차순으로 입력받는 것이 아니기 때문에 동일하게 42를 입력받아서 42로 나누어서 배열에 1 이라는 숫자가 저장되어 있다고해도 결국 순서대로 있지 않다.

이렇게 같은 나머지라도 순서대로 나오지는 않는다.

  • 사실 처음에는 모든 값을 하나하나 비교해서 갯수를 세어야하나? 라고 생각했었다. 하지만 그렇게 되면 결국 2중 for문을 돌리고 어쩌고하면서 오히려 복잡해지고, 뭣보다 아무리해도 서로 비교하게 놔두었을 때 중복되는 값들끼리 빅하는 것을 한번만 하도록 하는 방법을 찾지 못했다.
  • 결국 아침 잠결에 일어나서!!(정말로 잠자다가 일어났는데 불현듯 떠올랐다ㅋㅋㅋ) 생각해본 결과 배열에 저장된 값을 오름차순으로 정렬해두면 같은 값끼리는 이웃하게 되어 비교가 훨씬 편해지게 되었다.

위쪽 배열이 아래처럼 이쁘게 오름차순으로 정렬되었다.

  • 이렇게 정렬하여 비교하면 모든 값을 서로서로 비교할 필요가 없다는 점이다. 즉 버블 정렬을 활용하여 0번째와 1번째 1번째와 2번째 --- 8번째와 9번째 까지만 비교하면 된다. 왜냐하면 결국 동일한 숫자는 이웃하게 존재하는 배열이기에 서로 같은 값을 가지면 result 값이 올라가지 않는 상활이 된다. 이는 중복되는 값이 배열에는 존재하되, 다른 값을 확인 할 때는 존재하지 않는 것처럼 만들 수 있다(아래 코드로 좀 더 자세하게)
// 버블 정렬 사용해서 0번째와 1번째 비교, 1번째와 2번째 비교 ---- 8번째와 9번째까지 비교!
for(int j=0; j<array.length; j++) { 
	for(int k=j+1; k<array.length; k++) {
		if(array[j]!=array[k]) {
			bw.write("j 값 : "+j+"\n"); // 몇 번째 배열의 값이 동일하지 않은지 확인하기 위해
			bw.write("k 값 : "+k+"\n"); // 몇 번째 배열의 값이 동일하지 않은지 확인하기 위해	
			bw.newLine();
			bw.flush();
			result+=1; // 다를 경우 total +1
		}
		break; 
		// j 값이 1이상이 될때부터는 비교 하지 않고 바로 종료하게
		// 이를 통해 0번째값과 1번째 값, 1번째 값과 2번째 값 이렇게 비교할 수 있게 됨
	}
}
  • 코드를 보면서 조금 더 자세하게 확인할 수 있는데, 결국 우리에게 필요한 것은 서로 다른 값이 몇 개나 있는지 확인하는 것이다. 이 때문에 오름차순으로 정렬된 상태에서 비교하면 동일한 값은 비교할때 +1 되지도 않아서 사실상 ㅈ 중복된 값이 제거된 듯한 상황을 만들 수 있다.
  • 중간에 break를 사용하는 이유는 k for 문을 멈추기 위함인데 이는 array j 와 k 를 비교할때 딱 j와 k 까지만 비교하고, 그 이상이되는 k+1 +2 +3 +4 +5 이런식의 증가를 멈추는 것이라고 생각하면 된다. 결국 j = 0 , k = 0+1 과 비교하고 break, j= 1 , k= 1+1 하여 비교하고, break 같은 방식이다.

실제로 요런 식으로 딱 다른 값만 비교해서 찾는 것을 알 수 있다.

 

 

2. 1546 : 점수 조작해서 평균 구하기

N 개의 점수를 입력받고 , 점수 중 가장큰 최대값으로 각 점수를 나누고 * 100 을 한 후 그 점수로 다시 평균을 계산하여 기말고자 평균 구하기( 이 정도 노력이면 그냥 두었으면 합니다ㅎ)

여튼 문제풀이 시작!

	static void Q_1546() throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		
		float result = 0;
		int max = 0;
		
		int num = Integer.parseInt(br.readLine()); // N개의 숫자 입력받음
		String score = br.readLine(); // 점수 입력 받음

		String[] array = score.split(" "); // 입력받은 점수를 배열로 만들어버림
        
		System.out.println(Arrays.toString(array)); // 기존 점수 배열 한번 출력
		
		for(int i=0; i<num; i++) { // 몇 개의 점수를 입력받던지 num 개까지의 점수를 갖고 계산
			if(Integer.parseInt(array[i])>max) { // 최댓값 max 구함
				max = Integer.parseInt(array[i]); // 최댓값 구하기
			}
		}
		
		for(int j=0; j<num; j++) { // num 개 까지만 갖고 계산
			result += ((float)Integer.parseInt(array[j])/max*100)/num;
		}


		
//		System.out.println("big : "+big); // 최댓값 출력
//		System.out.println(Arrays.toString(n_score)); // 새로운 점수 배열 출력
		
		bw.write(result+"\n"); // result 출력
		br.close();
		bw.flush();
		bw.close();
		
	}
  • 이번 문제는 이전 문제보다 오히려 간단한 편이었다. 코드도 훨씬 간단한데, 변수 초기화 -> 최대값 구하기 -> 각 점수를 최댓값으로 나눈 후 *100 -> 이후 점수 평균 순서였다.
  • 사실상 최댓값 구하는 것은 전에 많이 풀었었고, 평균을 구하는 것도 이미 했던 부분이라 설명할 것도 거의 없을 듯하다.
  • 그나마 어려웠던 것은 num개만 입력받은 점수를 배열에 담는 부분정도였던것 같은데 저번과 달리 따로 나누고 어쩌고 하지 않고 그냥 몇 개의 점수던지 입력 받아 배열로 만들되, 내가 맨 처음에 입력받았던 num개 까지의 숫자만 갖고 계산을 진행하게 된다.

num=3 인 경우 40 80 60 10 20 30 모두 를 갖고 계산하는 것이 아닌 3번 인덱스 전까지 즉 40 80 60 만 갖고 계산한다.

  • 또한 평균은 실수이기 때문에 int 가 아닌 float 타입으로 해야했고, result 에 float 타입의 값으로 저장하기 위해 Integer.parseInt(array[j]) 할 때 앞에 float 로 붙여서 형변환하여 실수로 계산 될 수 있도록 해주었다.
for(int j=0; j<num; j++) {
	int plus+= (float)Integer.parseInt(array[j])/max*100 
    // 각 배열의 인덱스값을 max 값으로 나누고 100을 곱하고 모두 더함
    
    int average = plus/num; 
    // 모두 더한 값을 num 으로 나눔(num 개의 과목 점수기 때문에)
    
    // 위의 코드를 한 줄로 줄이면
    result += ((float)Integer.parseInt(array[j])/max*100)/num;
    
}

 

이번 문제들은 내가 설명하는게 사실 많이 힘들었다. 정석대로 푼 게 아니라 뭔가 내가 꼼수로? 푼 듯한 느낌이 많아서 오히려 힘들었던 것 같다.

 

고로 이글을 보시는 분들께서는 가능한 이클립스던 VS던 실행 후 직접 코드를 넣으셔서 실행해보시면서 설명해놓은 것을 보시면 훨씬!!! 많이 도움이 될 것이라고 생각합니다.

댓글