본문 바로가기
알고리즘/백준

백준 2840 행운의 바퀴 (JAVA 자바 풀이)

by Renechoi 2023. 6. 24.

백준 2840 행운의 바퀴 (JAVA 자바 풀이)

 


 

 

 


💡 풀이 과정 

 

구현, 시뮬레이션 문제이다. 문제에서 주어진 요구 사항을 그대로 구현하면 된다. 

 

첫번째로 입력받는 값을 임의로 설정하고 다음 순서로 들어오는 알파벳들을 배열에 채워준다. 

 

예제 입력으로 다음과 같이 주어지는 케이스를 생각해보자. 

5 6
1 A
2 B
5 B
1 C
2 A
2 B

 

먼저 바퀴가 5개라는 정보가 주어진다. 이는 배열의 크기가 5개보다 많을 수 없음을 나타내므로 5개 칸을 가진 배열을 만들어준다. 

 

StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());
int N = Integer.parseInt(stringTokenizer.nextToken());
int K = Integer.parseInt(stringTokenizer.nextToken());

char[] wheel = new char[N];

 

그런 후 하나씩 채우면 되는데, 맨 처음 정보에서 주어지는 숫자는 무시해도 좋다. 

 

임의로 설정할 때 계산상 편의를 고려해 0번째로 초기화해주었다. 

 

if (wheel[0] == '\u0000') {
   wheel[0] = current;
   continue;
}

 

이후 들어오는 값들의 성격을 생각해보면 배열이 순환형으로 돌아야 하기 때문에 카운트 값을 정해주고 만약 해당 카운트가 배열 크기를 벗어나면 처음으로 돌아오는 것을 생각하면 된다. 

 

예를 들어 2번째로 들어오는 2번은 0번째로 초기화된 A보다 2가 많으므로 idx 값을 2로 설정할 수 있고, 이 값은 배열의 크기 5를 벗어나지 않으므로 무리 없이 배열에 추가해줄 수 있다. 

 

wheel[updateIdx] = current;

 

 

그 다음을 생각해보자. 

 

이번에는 5와 B가 들어온다. 이때 현재 인덱스인 2에 5를 더한 값 7은 배열의 크기 5를 벗어나되, 2만큼을 벗어난다. 따라서 원형 배열에서 한바퀴를 돌고 다시 2만큼 옆으로 간 상황이라고 할 수 있다. 이때 현재 배열 상태는 

[A, _, B, _, _] 이므로 기존의 입력된 B와 같은 위치이다. 

 

이 경우엔 별도로 해줄 것이 없으므로 그대로 채워주거나 넘겨도 된다. 

 

 

// 같은 것이 들어있는 경우
if (wheel[updateIdx] == current) {
   // wheel[updateIdx] = current;
   return;
}

 

 

다음 케이스를 보면 C가 1의 위치를 갖고 들어온다. 즉, 현재 인덱스인 2에 1이 더한 값 3의 위치에 C를 초기화해줄 수 있다. 

 

이렇게 각각을 제자리에 맞게 넣어주면 최종적으로는 

 

[A, _, B, C, _] 배열이 된다. 

 

문제의 요구 사항에 따라 빈값은 물음표로 출력해주면 되고, 요구사항에 맞게 출력을 마지막 위치부터 해주면 된다. 원형 배열의 특징에 따라 뒤에서부터 출력을 해주고, 남는 값이 있을 것으로 고려해 맨 마지막부터 한 번 더 출력을 해준다. 

 

for (int i = updateIdx; i >= 0; i--) {
   char update = wheel[i]== '\u0000' ? '?' : wheel[i];
   stringBuilder.append(update);
}

for (int i = wheel.length - 1; i > updateIdx; i--) {
   char update = wheel[i]== '\u0000' ? '?' : wheel[i];
   stringBuilder.append(update);

 

 

 

이 문제에서 주의할 점은 다음과 같은 케이스들을 잘 나누어야 한다는 점이다. 

 

 

// 같은 것이 들어있는 경우
if (wheel[updateIdx] == current) {
   // wheel[updateIdx] = current;
   return;
}

// 비어있는 경우 && 중복이 아닌경우
if (wheel[updateIdx]== '\u0000' && !duplicate(current, wheel)) {
   wheel[updateIdx] = current;
   return;
}

// 다른 것이 들어있거나 중복인 경우
throw new IllegalArgumentException();

 

문제에서 "바퀴에 같은 글자는 두 번 이상 등장하지 않는다."라는 조건에 따라 중복인 경우를 체크해주어야 했다. 이점을 체크하지 못해 초기 시도에서 실패를 했다. 

 

중복은 다음과 같이 체크를 해줄 수 있다.

private static boolean duplicate(char current, char[] wheel) {
   return IntStream.range(0, wheel.length).mapToObj(i-> wheel[i]).anyMatch(alphabet -> alphabet == current);
}

 

참고로 캐릭터 배열을 스트림으로 변환하는 과정에 관한 내용은 다음 글에서 자세히 볼 수 있다. 

 

https://upcurvewave.tistory.com/438

 

왜 int, String 배열은 스트림(Stream)으로 쉽게 변환되는데 char 배열은 안 되는 것일까?! (자바 캐릭터

Java.util 패키지의 Arrays 클래스를 이용하면 간단히 Stream으로 변경할 수 있다. 위에서와 int 외에도 다양한 숫자형 strem 변환을 지원한다. public class Example { public static void main(String[] args) { toStream(new i

upcurvewave.tistory.com

 

 

 

💡 코드 구현

 


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.stream.IntStream;

public class Main {

	private static final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));

	public static void main(String[] args) throws IOException {

		StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());
		int N = Integer.parseInt(stringTokenizer.nextToken());
		int K = Integer.parseInt(stringTokenizer.nextToken());

		char[] wheel = new char[N];
		int arrow = 0;
		int updateIdx = 0;
		while (K-- > 0) {
			stringTokenizer = new StringTokenizer(bufferedReader.readLine());
			int change = Integer.parseInt(stringTokenizer.nextToken());
			char current = stringTokenizer.nextToken().charAt(0);

			if (wheel[0] == '\u0000') {
				wheel[0] = current;
				continue;
			}

			arrow += change;
			updateIdx = arrow % N;
			try {
				updateWheel(current, updateIdx, wheel);
			} catch (Exception e) {
				System.out.println("!");
				return;
			}
		}

		System.out.print(createAnswer(wheel, updateIdx));
	}


	private static String createAnswer(char[] wheel, int updateIdx) {
		StringBuilder stringBuilder = new StringBuilder();

		for (int i = updateIdx; i >= 0; i--) {
			char update = wheel[i]== '\u0000' ? '?' : wheel[i];
			stringBuilder.append(update);
		}

		for (int i = wheel.length - 1; i > updateIdx; i--) {
			char update = wheel[i]== '\u0000' ? '?' : wheel[i];
			stringBuilder.append(update);
		}
		return stringBuilder.toString();
	}

	private static void updateWheel(char current, int updateIdx, char[] wheel) {

		// 같은 것이 들어있는 경우
		if (wheel[updateIdx] == current) {
			// wheel[updateIdx] = current;
			return;
		}

		// 비어있는 경우 && 중복이 아닌경우
		if (wheel[updateIdx]== '\u0000' && !duplicate(current, wheel)) {
			wheel[updateIdx] = current;
			return;
		}

		// 다른 것이 들어있거나 중복인 경우
		throw new IllegalArgumentException();

	}

	private static boolean duplicate(char current, char[] wheel) {
		return IntStream.range(0, wheel.length).mapToObj(i-> wheel[i]).anyMatch(alphabet -> alphabet == current);
	}
}

 

 

 

 

 

 

 

반응형