[프로그래머스] 안전지대.JS

ungnam·2023년 6월 6일

programmers level0

목록 보기
18/29
post-thumbnail

https://school.programmers.co.kr/learn/courses/30/lessons/120866

나의 풀이

처음 시도한 풀이

function solution(board) {
    const n = board.length;
    const flatten = board.flat();
    
    for (let i = 0; i < n*n; i++) {
        if (flatten[i] === 1) {
            const dangerZone = [i-1-n, i-n, i+1-n, i-1, i+1, i-1+n, i+n, i+1+n].filter((v) => v >= 0 && v < n*n);
            dangerZone.forEach((v) => {
                if (!flatten[v]) {
                    flatten[v] = "X";
                }
            })
        }
    }
    
    return flatten.filter((v) => !v).length;
}

✔ "2차원으로 된 배열을 1차원으로 바꾸면 훨씬 더 수월하게 해결할 수 있지 않을까?" 하는 생각으로 flat() 메소드를 통해 board를 평탄화시킴
✔ 폭탄의 위치를 제외한 나머지 8칸에 대해 0 미만이거나 n*n 이상의 인덱스를 가지는 부분은 배열의 범위에 벗어나기 때문에 제외
filter된 칸 중 0인 부분만 위험 지역을 뜻하는 X로 마킹

❗ 결과는... 테스트 케이스 7번을 통과하지 못해서 실패😭

무엇이 문제였을까?

지뢰가 왼쪽 끝이나 오른쪽 끝에 있을 경우에 문제가 발생한다.

예를 들어,

1 1 0 0
1 1 0 0
0 0 0 0
0 0 0 0

의 경우 (0,0)에 위치한 1의 경우 dangerZone[-5, -4, -3, -1, 1, 3, 4, 5]가 되는데, (0,0)왼쪽 아래의 경우 board에서는 배열의 범위를 벗어나게 되지만 평탄화시켰을 때는 i-1+n에 의해 flatten3번째 인덱스를 가리키게 된다.
따라서 쌩뚱맞은 위치에 위한 flatten[3]X가 마킹이 된다.

즉, 1차원과 2차원 배열의 기본적인 특성 차이를 망각해버려서 생겨버린 문제였다..

최종 풀이

결론은, 그냥 정석대로 "2차원 배열로 풀자!" 였다.😅

function solution(board) {
    const n = board.length;
    
    for (let r = 0; r < n; r++) {
        for (let c = 0; c < n; c++) {
            if (board[r][c] === 1) {
                const dangerZone = [
                    [r-1, c-1], [r-1, c], [r-1, c+1], 
                    [r, c-1], [r, c+1], 
                    [r+1, c-1], [r+1, c], [r+1, c+1]
                ];
                dangerZone
                    .filter((v) => (v[0] >= 0 && v[0] < n) && (v[1] >= 0 && v[1] < n))
                    .forEach((v) => {
                        if (!board[v[0]][v[1]]) {
                            board[v[0]][v[1]] = "X";
                        }
                    });
            }
        }
    }
    
    return board.flat().filter((v) => !v).length;
}

✔ 위험지역의 좌표들을 dangerZone 2차원 배열에 저장
filter를 통해 배열의 범위 밖의 좌표를 제외
flat를 통해 1차원으로 펼친 다음 0의 개수를 리턴

참고할 만한 풀이

function solution(board) {

    let outside = [[-1,0], [-1,-1], [-1,1], [0,-1],[0,1],[1,0], [1,-1], [1,1]];
    let safezone = 0;

    board.forEach((row, y, self) => row.forEach((it, x) => {
        if (it === 1) return false;
        return outside.some(([oy, ox]) => !!self[oy + y]?.[ox + x])
               ? false : safezone++;
    }));

    return safezone;
}

되게 풀이가 간소화된 방법인 것 같아서 가져와봤다.
✔ 나처럼 위험지역의 좌표를 직접 표현하지 않고 outside에 상대적인 벡터값을 저장하였다.
?.(optional chaining)을 사용하여 self[oy + y]가 존재하지 않으면 아예 self[oy + y]?.[ox + x]undefined가 되도록! -> 에러 방지
✔ 지뢰를 기준으로 주변을 보는게 아닌 주변에 지뢰가 있는지 확인하는 접근 방식 -> 아주 참신하다.
forEach의 세 번째 인자로 자기 자신, 즉 board를 가져올 수 있다. 여기에 변경을 가하게 되면 원본도 변경이 적용된다는 점!

profile
꾸준함을 잃지 말자.

0개의 댓글