Algorithm/Programmers

[Lv.3] 자물쇠와 열쇠

시롱시롱 2023. 4. 13. 11:35

삽질코드(82/100)

import java.util.ArrayList;
import java.util.List;

class Solution {
    public boolean solution(int[][] key, int[][] lock) {
        int n=lock.length;
        List<Point> lockPoints=new ArrayList<>();
        Point initPoint,endPoint;
        initPoint=new Point(n,n);
        endPoint=new Point(-1,-1);
        for (int i = 0; i < lock.length; i++) {
            for (int j = 0; j < lock[i].length; j++) {
                if(lock[i][j] == 0){
                    lockPoints.add(new Point(i,j));
                    if(i< initPoint.x)
                        initPoint=new Point(i, initPoint.y);
                    if(j< initPoint.y)
                        initPoint=new Point(initPoint.x, j);
                    if(i> endPoint.x)
                        endPoint=new Point(i, endPoint.y);
                    if(j> endPoint.y)
                        endPoint=new Point(endPoint.x, j);

                }
            }
        }
        //왼위 오아래 기준으로 직사각형을 만들어서 자르자
        //그 직사각형이 pXq라면
        //Key를 어떻게 어떻게 해서 pXq 형태로 만들고 이게 맞는 지 확인해야 할 듯..
        int sqrX= endPoint.x- initPoint.x;
        int sqrY= endPoint.y- initPoint.y;
        //여기서 1,1 ` 1,2 이렇게 1x2 직사각형인 경우 sqrx=0, sqry=1
        int lockSize=lockPoints.size();
        if(lockSize==0) {
            return false;
        }
        //lock의 init을 0 으로 잡고 LockPoint를 다시 설정한다.
        Point finalInitPoint = initPoint;
        for (int i = 0; i < lockPoints.size(); i++) {
            Point point = lockPoints.get(i);
            point.x= point.x- finalInitPoint.x;
            point.y= point.y- finalInitPoint.y;
        }


        for (int i = 0; i < key.length; i++) {
            for (int j = 0; j < key.length; j++) {
                if(j+sqrY< key.length&&i+sqrX<key.length){
                    List<Point> targetKeyList1=new ArrayList<>();
                    List<Point> targetKeyList2=new ArrayList<>();
                    List<Point> targetKeyList3=new ArrayList<>();
                    List<Point> targetKeyList4=new ArrayList<>();
                    for (int k = i; k <= i+sqrX; k++) {
                        for (int l = j; l <= j+sqrY; l++) {
                            if(key[k][l]==1) {
                                //왼위 부터 검사를 시작하고 그걸 0으로 봐야한다
                                targetKeyList1.add(new Point(k-i,l-j));
                                targetKeyList2.add(new Point(l-j,sqrX-(k-i)));
                                targetKeyList3.add(new Point(sqrX-(k-i),sqrY-(l-j)));
                                targetKeyList4.add(new Point(sqrY-(l-j),k-i));
                            }
                            if(lockSize<targetKeyList1.size()){
                                break;
                            }
                        }
                    }
                    if(targetKeyList1.size()!=lockSize)
                        continue;
                    if(lockPoints.containsAll(targetKeyList1)||lockPoints.containsAll(targetKeyList2)
                            ||lockPoints.containsAll(targetKeyList3)||lockPoints.containsAll(targetKeyList4)){
                        return true;
                    }
                }
                if(i+sqrY< key.length&&j+sqrX<key.length){
                    List<Point> targetKeyList1=new ArrayList<>();
                    List<Point> targetKeyList2=new ArrayList<>();
                    List<Point> targetKeyList3=new ArrayList<>();
                    List<Point> targetKeyList4=new ArrayList<>();
                    for (int k = i; k <= i+sqrY; k++) {
                        for (int l = j; l <= j+sqrX; l++) {
                            if(key[k][l]==1) {
                                //왼위 부터 검사를 시작하고 그걸 0으로 봐야한다
                                targetKeyList1.add(new Point(k-i,l-j));
                                targetKeyList2.add(new Point(l-j,sqrY-(k-i)));
                                targetKeyList3.add(new Point(sqrY-(k-i),sqrX-(l-j)));
                                targetKeyList4.add(new Point(sqrX-(l-j),k-i));
                            }
                            if(lockSize<targetKeyList1.size()){
                                break;
                            }
                        }
                    }
                    if(targetKeyList1.size()!=lockSize)
                        continue;
                    if(lockPoints.containsAll(targetKeyList1)||lockPoints.containsAll(targetKeyList2)
                            ||lockPoints.containsAll(targetKeyList3)||lockPoints.containsAll(targetKeyList4)){
                        return true;
                    }
                }

            }
        }

        return false;
    }
    class Point{
        int x;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Point point = (Point) o;

            if (x != point.x) return false;
            return y == point.y;
        }

        @Override
        public int hashCode() {
            int result = x;
            result = 31 * result + y;
            return result;
        }

        int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}

정답코드

import java.util.*;

class Solution {
    public boolean solution(int[][] key, int[][] lock) {
        boolean answer = true;

        int m = key.length;
        int n = lock.length;

        int len = n+m*2-2;
        int[][] map = new int[len][len];    // 확장시킨 배열

        /* 확장시킨 배열에 Lock 표시 */
        for(int i=m-1; i<m+n-1 ; i++){
            for(int j=m-1; j<m+n-1; j++){
                map[i][j] = lock[i-(m-1)][j-(m-1)];
            }
        }

        /* 4번 조사 */
        for(int i=0; i<4; i++){
            if(check(map, key, n)){
                return true;
            }
            rotate(key); // 시계방향 90도 회전
        }


        return false;
    }

    /* 키가 자물쇠에 맞는지 체크 */
    public static boolean check(int[][] map, int[][] key, int lockLen){
        int keyLen = key.length;
        int mapLen = map.length;
        for(int i=0; i<mapLen-keyLen+1; i++){
            for(int j=0; j<mapLen-keyLen+1; j++){

                /* map에 key를 더함 */
                for(int k=0; k<keyLen; k++){
                    for(int l=0; l<keyLen; l++){
                        map[i+k][j+l] += key[k][l];
                    }
                }

                /* 자물쇠 부분이 전부 1이 됐는지 확인 */
                boolean flag = true;
                for(int k=keyLen-1; k<keyLen+lockLen-1; k++){
                    for(int l=keyLen-1; l<keyLen+lockLen-1; l++){
                        if(map[k][l] != 1){ // 1이 아니면 홈이 안 맞는 것임
                            flag = false;
                            break;
                        }
                    }
                    if(!flag) break;
                }

                if(flag) return true;   // 전부 1이였다면 true

                /* map을 원상 복귀 시킴 -> map에서 key를 뺌 */
                for(int k=0; k<keyLen; k++){
                    for(int l=0; l<keyLen; l++){
                        map[i+k][j+l] -= key[k][l];
                    }
                }

            }
        }

        return false;
    }

    /* key 시계 방향 90도 회전 */
    public static void rotate(int[][] key){
        int len = key.length;
        int[][] temp = new int[len][len];

        for(int i=0; i<len; i++){
            for(int j=0; j<len; j++){
                temp[i][j] = key[len-j-1][i];
            }
        }

        for(int i=0; i<len; i++){
            for(int j=0; j<len; j++){
                key[i][j] = temp[i][j];
            }
        }

    }
}

 

 


엄청난 삽질을 한 문제였다.

난, 열쇠로 자물쇠를 푸는 게 열쇠를 회전하고 초콜릿 떼어내듯이 아래로 한 칸 밀면 아래 한칸을 떼어내고 옆으로 또 밀면 옆에 한 줄을 또 떼내는 방식인줄 알았다....

처음 코드를 냈을 땐, 15번 이후의 케이스들이 오류를 내더니 수정하여 제출하니 앞번호의 케이스들이 오류를 냈다.

로직에 문제는 없는 것 같아 문제를 다시 보니 민다는 뜻이 열쇠 판을 자물쇠 판 기준 빈공간으로 밀면서 끼워 넣는 것이였다.(마치 손바닥 맞대듯이..)

이러한 문제가 sliding window 라는 유형인데, 처음 풀어봐서 그런지 접근 방법을 잘 못 잡은 것 같다.

다음에 sliding window 문제를 만나면 꼭 눈치채고 바로바로 풀어야 겠다..