Softeer [인증평가(3차) 기출] 플레이페어 암호 - 자바 JAVA

루리·2022년 11월 4일
0

알고리즘

목록 보기
2/7

[소프티어][인증평가(3차) 기출] 플레이페어 암호

문제 링크

문자열 문제는 평소에 안 풀어서 현대오토에버 전 날 연습 겸 풀어봤다. 외부 IDE(Eclipse) 사용해서 약 40분 정도 소요되었다.

새로 알게 된 것

1) Character.valueOf(char c)

  • ArrayList에서 remove를 할 때, remove(Object o)보다 remove(int index)가 먼저 인식되기 때문에 (타입).valueOf를 사용하여 값을 넣어줘야 한다.
list.remove(Character.valueOf(arr[r][c]));
  • 추가로 String.valueOf(Object o), Integer.valueOf(int i || String s), Boolean.valueOf(boolean b || String s) 등도 있다.

2) sb.insert(int offset, Object o);

  • StringBuilder의 insert를 사용하여 String 원하는 인덱스에 값을 끼워 넣을 수 있다.
sb.insert(idx + 1, 'X');

3) sb.setCharAt(int index, char c);

  • StringBuilder에서 원하는 인덱스의 Character 값을 바꿀 수 있다.
sb.setCharAt(idx, arr[cx][c2y]);
sb.setCharAt(idx + 1, arr[c2x][cy]);

4) sb.reverse();

  • 문제 푸는 데에 사용한 것은 아니고 StringBuilder의 method 목록을 구경하다가 찾았다. StringBuilder에서 String을 뒤집을 수 있다.

substring, split 할 때는 String, 나머지 경우에는 StringBuilder를 사용하는 것이 좋다고 들었다.
기존에는 테스트 케이스가 많은 문제를 풀 때 출력하는 용도로만 사용했었는데, 앞으로 문자열 구현 문제를 풀 때 String을 사용하는 것도 좋지만 StringBuilder를 적극 활용해 봐야겠다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Main_1105 {
//	[인증평가(3차) 기출] 플레이페어 암호
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String str = br.readLine();
		String pri = br.readLine();
		char[][] arr = new char[5][5];
		List<Character> alphabet = new ArrayList<>();

		// 알파벳 리스트 만들기
		for (int i = 0; i < 26; i++) {
			if ((char) 'A' + i == 'J') {
				continue;
			}
			alphabet.add((char) ('A' + i));
		}
		int r = 0;
		int c = 0;

		// 배열에 넣기
		for (int i = 0; i < pri.length(); i++) {
			if (alphabet.contains(pri.charAt(i))) {
				arr[r][c] = pri.charAt(i);
				alphabet.remove(Character.valueOf(arr[r][c]));
				c++;
				if (c == 5) {
					c = 0;
					r++;
				}
			}
		}

		// 나머지 알파벳 넣기
		for (int i = 0; i < alphabet.size(); i++) {
			arr[r][c] = alphabet.get(i);
			c++;
			if (c == 5) {
				c = 0;
				r++;
			}
		}

		// 배열 출력해보기
//		for (int i = 0; i < arr.length; i++) {
//			for (int j = 0; j < arr.length; j++) {
//				System.out.print(arr[i][j] + " ");
//			}
//			System.out.println();
//		}

		// 두 글자씩 이루어진 쌍 파괴하기
		StringBuilder sb = new StringBuilder();
		sb.append(str);
		int idx = 0;
		while (idx < sb.length() - 1) {
			if (sb.charAt(idx) == sb.charAt(idx + 1)) {
				// XXX가 될 경우
				if (sb.charAt(idx) == 'X') {
					sb.insert(idx + 1, 'Q');
				} else {
					sb.insert(idx + 1, 'X');
				}
			}
			idx += 2;
		}

		// 만든 String이 홀수 길이일 경우 맨 뒤에 X 추가
		if (sb.length() % 2 == 1) {
			sb.append('X');
		}
//		System.out.println(sb);

		idx = 0;
		while (idx < sb.length() - 1) {
			char c1 = sb.charAt(idx);
			char c2 = sb.charAt(idx + 1);
			int cx = 0, cy = 0, c2x = 0, c2y = 0;

			for (int i = 0; i < 5; i++) {
				for (int j = 0; j < 5; j++) {
					if (c1 == arr[i][j]) {
						cx = i;
						cy = j;
					}
					if (c2 == arr[i][j]) {
						c2x = i;
						c2y = j;
					}
				}
			}
			// 같은 행에 존재할 경우
			if (cx == c2x) {
				if (cy + 1 >= 5)
					cy = -1;
				if (c2y + 1 >= 5)
					c2y = -1;
				sb.setCharAt(idx, arr[cx][cy + 1]);
				sb.setCharAt(idx + 1, arr[c2x][c2y + 1]);
				idx += 2;
				continue;
			}

			// 같은 열에 존재할 경우
			if (cy == c2y) {
				if (cx + 1 >= 5)
					cx = -1;
				if (c2x + 1 >= 5)
					c2x = -1;
				sb.setCharAt(idx, arr[cx + 1][cy]);
				sb.setCharAt(idx + 1, arr[c2x + 1][cy]);
				idx += 2;
				continue;
			}

			// 서로 다른 행,열에 존재하면 열을 서로 교환한다.
			sb.setCharAt(idx, arr[cx][c2y]);
			sb.setCharAt(idx + 1, arr[c2x][cy]);
			idx += 2;
		}
		System.out.println(sb);
	}

}
profile
안녕하세요

1개의 댓글

comment-user-thumbnail
2024년 2월 19일

진짜 잘 짜셨네요.. 어떻게 풀지 막막했는데 덕분에 이해했습니다.

답글 달기