Algorithm

[JAVA] Softeer 소프티어 플레이페어 암호

랩실외톨이 2022. 11. 5. 02:29
반응형

https://softeer.ai/practice/info.do?idx=1&eid=804&sw_prbl_sbms_sn=101449 

 

Softeer

연습문제를 담을 Set을 선택해주세요. 취소 확인

softeer.ai

 

1. 서론

 

Level 3 문제라는데 Softeer에서 Level 3이 어느 수준인지 모르겠다. 어쨌든 조건이 꽤 있는 시뮬레이션 문제다. 빡구현이 답.

(근데 생각지도 못한 곳에서 자꾸 틀림 ㅜ)

2. 문제 풀이

 

처음에는 문제 이해도 안 갔는데 찬찬히 읽다 보니까 알게 되었다.

 

1.
주어진 문자열로 배열을 채우는데 사용한 알파벳은 두 번 사용안 함. 남은 자리는 나오지 않은 알파벳을 순서대로 채움.

2.
암호화할 문자열을 두 글자씩 쪼갬
근데 두 글자가 같다면 두 글자 사이에 x를 넣음
근데 xx라면 q를 넣음
이렇게 쌍을 맞췄는데 마지막에 한 글자가 남으면 뒤에 x를 붙임

3.
3-1.
두 글자가 표에서 같은행에 존재한다면 가로로 밀기
암호화는 표에서 한칸씩 밀어서 함
근데 a[0][4] -> a[0][0] 이렇게 밀어야 함 

3-2.
근데 위의 경우를 만족하지 않으면서 두 글자가 표에서 같은 열에 존재하면
가로가 아니라 세로로 밀기

3-3.
서로 다른 행에 존재하면
ex)
a[0][1], a[4][3]에 존재한다면 
a[0][3], a[3][1]에 있는 글자로 대치
즉, 서로 j값 교환

 

이 순서대로 각각 역할을 해주는 로직을 구현했다.

근데 주어진 테케가 맞았는데 자꾸 틀렸습니다가 떠서 뭐지 하고 코드를 이것저것 고쳤는데 정확히 뭐가 문제인지를 모르다가 테케 하나를 만들어서 넣어봤더니 틀린 걸 찾았다.

바로 HEX. 1번에 있는 문자열을 그대로 가져오고 암호화 문자열만 바꿨다.

문제는 HEX라면 겹치는 것은 없지만 2개로 나눠지지 않기 때문에 마지막에 X를 붙여 HEXX가 된다.

그러면 EIZZ가 나와야하는데 EIXX가 나와버린 것이다.

나는 if (보드 == 앞글자 || 보드 == 뒷글자) 이런 식으로 해서 cnt를 해줘서 2개이면 로직이 실행되게 했는데 (왜냐면 이 경우를 제외하면 앞, 뒤의 두 글자가 겹치는 경우가 없기 때문에) 그러다 보니 cnt가 한 개만 돼서 자꾸 테케가 틀리게 된 것이다. 이것 때문에 거의 한 시간 날린 듯.

 

3. 코드 설명

 

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


public class Main
{
    public static void main(String args[]) throws Exception
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        String s = br.readLine();
        String pc = br.readLine();

        char[][] board = new char[5][5];
        int[] check = new int[26];
        int i = 0, j = 0;

    
        //check 배열에서 board에 넣는 알파벳 체크 
        for (int k = 0; k < pc.length(); k++) {
            if (check[pc.charAt(k) - 'A'] == 0) 
                board[i][j++] = pc.charAt(k);
            check[pc.charAt(k) - 'A']++; 

            if (j == 5) {
                i++; j = 0;
            }
        }

        //check 배열에서 0인 값을  board에 넣음
        for (int k = 0; k < 26; k++) {
            if (check[k] == 0 && k != 9) //j처리
                board[i][j++] = (char)(k + 'A');
            if (j == 5) {
                i++; j = 0;
            }
        }
        
        //문자열 두 개씩 쪼갬
        StringBuilder t = new StringBuilder();
        for (int k = 0; k < s.length(); k+=2) {
            t.append(s.charAt(k));
            if (k == s.length() - 1) { //한 개만 남은 경우
                t.append('X');
                break; 
            }
            if (s.charAt(k) == s.charAt(k + 1)) { //X or Q
                if (s.charAt(k) != 'X')
                    t.append('X');
                else
                    t.append('Q');
                k--; //하나 추가해 줬기 때문에 두 번째 같은 문자부터 다시 탐색
            }
            else 
                t.append(s.charAt(k + 1));
        }

        StringBuilder ans = new StringBuilder();
        for (int k = 0; k < t.length(); k+=2) {
            int f = 0;
            for (i = 0; i < 5; i++) { //같은 행에 있는 경우
                int cnt = 0;
                for (j = 0; j < 5; j++) {
                    if (board[i][j] == t.charAt(k))
                        cnt++;
                    if (board[i][j] == t.charAt(k + 1))
                        cnt++;
                }

                if (cnt == 2) {
                    for (j = 0; j < 5; j++) {
                        if (board[i][j] == t.charAt(k)) {
                            if (j + 1 < 5)
                                ans.append(board[i][j + 1]);
                            else
                                ans.append(board[i][0]);
                            break;
                        }
                    }
                    for (j = 0; j < 5; j++) {
                        if (board[i][j] == t.charAt(k + 1)) {
                            if (j + 1 < 5)
                                ans.append(board[i][j + 1]);
                            else
                                ans.append(board[i][0]);
                            break;
                        }
                    }
                    f = 1;
                    break;
                }
            }

            if (f == 0) { //같은 열에 있는 경우
                for (i = 0; i < 5; i++) {
                    int cnt = 0;
                    for (j = 0; j < 5; j++) {
                        if (board[j][i] == t.charAt(k))
                            cnt++;
                        if (board[j][i] == t.charAt(k + 1))
                            cnt++;
                    }

                    if (cnt == 2) {
                        for (j = 0; j < 5; j++) {
                            if (board[j][i] == t.charAt(k)) {
                                if (j + 1 < 5)
                                    ans.append(board[j + 1][i]);
                                else
                                    ans.append(board[0][i]);
                                break;
                            }
                        }
                        for (j = 0; j < 5; j++) {
                            if (board[j][i] == t.charAt(k + 1)) {
                                if (j + 1 < 5)
                                    ans.append(board[j + 1][i]);
                                else
                                    ans.append(board[0][i]);
                                break;
                            }
                        }
                        f = 1;
                        break;
                    }
                }
            }

            if (f == 0) { // 서로 다른 행, 열에 있는 경우
                int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
                for (i = 0; i < 5; i++) {
                    for (j = 0; j < 5; j++) {
                        if (board[i][j] == t.charAt(k)) {
                            x1 = i;
                            y2 = j;
                        }
                           
                        if (board[i][j] == t.charAt(k + 1)) {
                            x2 = i;
                            y1 = j;
                        }
                            
                    }
                }
                ans.append(board[x1][y1]);
                ans.append(board[x2][y2]);
            }  
        }
        bw.write(ans.toString());
        bw.close(); br.close();
    }
}

 

위에 적힌 로직을 그대로 구현해줬다. 각각 3-1,2,3을 순서대로 구현해서 위의 것에 해당되면 f로 식별하고 break를 해서 반복문을 멈추게 만들었다.

 

만약에 이게 실제 문제였으면 난 히든에 걸려서 틀렸겠지.... 진짜 조심하고 모든 케이스를 다 생각하면서 풀어야 하는 것 같다 ㅠㅠ

 

 

 

 

반응형