[programmers] 행렬 테두리 회전하기 #JavaScript

·2021년 8월 29일
0

Coding Test

목록 보기
1/3
post-thumbnail

LEVEL 2 : 행렬 테두리 회전하기

  • IN
    rows, columns, queries
  • OUT
    회전한 숫자 중 min

먼저, rows * columns 크기의 2차원 배열을 만들어준다..!
그리고 1 부터 rows * columns 까지 숫자를 순서대로 하나씩 넣어줄 것이다.


var arr = []; // 숫자 행렬을 만들 변수

for(var i = 0; i<rows ; i++){ // 행수 만큼 돌리기
  var a = []; // 임시 배열
  for(var j = 0 ; j<columns ; j++){ // 열수 만큼 돌리기
    a.push(columns * i + j + 1); // 숫자 하나씩 배열 만들기
  }
  arr.push(a); // 배열 한 줄 넣기
}

숫자 순서대로 넣을 규칙을 찾아냈다..!
배열의 index 는 0으로 시작하니 0부터 기준을 잡고,
한 줄에 1부터 columns 까지 채운다면,
이 줄의 규칙은 j+1!


다음 줄에서도 1부터 columns 까지 채운다.
물론, 이전 줄 길이 값인 columns을 더해준다.
호옹이 뭔가 벌써 규칙이 보이기 시작했지 않은가...!


아니, 아직 모를 수 도 있다. 다시 다음 줄을 진행해본다.

1부터 columns 까지 채우기 전에!! 이전 줄 길이 값인 columns 를 두번 더해준다. 왜냐구? 이전 줄이 두 줄이잖아~
유레카! columns이 어떠한 배수로 증가하는 거 같다.

여기서 잠깐!
임의의 정수 N에 대하여 0을 곱하면 0, 1을 곱하면 N이다.
그럼 여기서 살짝 아쉬운 부분에 손을 살짝 대보았다.
그 어떠한 숫자는 0부터 증가중인 것을 볼 수 있다. 바로 i 였다.
요로코롬 columns * i + j + 1 도출!
(어차피 곱셈 연산 우선순위가 높으니, 괄호는 모두 생략)

제한사항에 "i 행 j 열에 있는 숫자는 ((i-1) x columns + j)입니다." 라고 친절히 적혀있었지만,
까막눈봄씨는 그림을 그려 규칙을 찾아냈다는 슬픈 이야기였다...

물론, 게시글은 깔끔하게 보이기 위해 엑셀로 정리^^

.push() 를 이용하여 값 하나씩 넣어 1차원 배열을 만들었고,
이렇게 만들어진 1차원 배열을 또 다른 1차원 배열에 push!!

너무 자바스럽나..? 이 외에 더 간단한 방법이 있을 거 같다.

REF. 충격적인!! 어느 한 분의 한 줄 숏코딩

const a = [...Array(rows)].map((_, r)=>[...Array(columns)].map((_, c)=>r*columns+c+1));

JS린이는 해석도 못하겠습니다만... 득도하겠습니다..


이제 다음 단계!! 숫자 돌려돌려 돌림판~~


queries.forEach(e => {
  // index 기준으로 세팅
  var x1 = e[0] -1;
  var y1 = e[1] -1;
  var x2 = e[2] -1;
  var y2 = e[3] -1;

  var min = rows * columns; // 회전수 중 최솟값
  var tmp = arr[x1][y2]; // 숫자 회전을 위한 임시 변수
        
  // 1
  for(var a = y1; a < y2 ; a++ ){ // x1 고정
    var t =  arr[x1][a];
    arr[x1][a] = tmp;
    tmp = t;

    if( arr[x1][a] <= min ){
      min = arr[x1][a];
    }
  }
  // 2
  for(var b = x1; b < x2 ; b++ ){ // y2 고정
    var t =  arr[b][y2];
    arr[b][y2] = tmp;
    tmp = t;

    if( arr[b][y2] <= min ){
      min = arr[b][y2];
    }
  }
  // 3
  for(var c = y2; c > y1 ; c-- ){ // x2 고정
    var t =  arr[x2][c];
    arr[x2][c] = tmp;
    tmp = t;

    if( arr[x2][c] <= min ){
      min = arr[x2][c];
    }
  }
  // 4
  for(var d = x2; d > x1 ; d-- ){ // y1 고정
    var t =  arr[d][y1];
    arr[d][y1] = tmp;
    tmp = t;

    if( arr[d][y1] <= min ){
      min = arr[d][y1];
    }
  }
  // 마무리
  arr[x1][y1] = tmp;
  
  if( arr[x1][y1] <= min ){
    min = arr[x1][y1];
  }

  answer.push(min);
});

어디서 본 건 있어서... forEach 를 써보았다..!
queries의 행수만큼 루프 돌 것이다.

queries 데이터는 "1 ≤ x1 < x2 ≤ rows, 1 ≤ y1 < y2 ≤ columns"
로 지정되어 있으니, 입력값 검증은 안해도 무관~
다만 배열 index 기준으로 코딩을 위해 다들 -1 해줍니다.

최솟값을 저장할 변수는 행렬 내 가장 큰 값으로 default~


이제 그림을 또 그려 볼까요..?

처음에는 무작정 이중for문으로 순서대로 돌렸는데, 시계방향 회전이었다..! 바본가?
그래서 코로NA도 4단계인김에 회전도 4단계로 나누었다.
(이것은 마무리까지 4.5단계?ㅎ)

1번째 회전에선 y1 고정, x 증가
2번째 회전에선 x2 고정, y 증가
3번째 회전에선 y2 고정, x 감소
4번째 회전에선 x1 고정, y 감소

각 꼭짓점은 시작점만 포함해서 돌리기로 한다.

제일 처음에는 임시 변수 tmp에 1번째 시작점 값을 넣는다.
회전시에 각 점의 값과 tmp 값을 swapping! 그것을 반복~!

swapping 하는 김에 최소값인지까지 확인해주기로 하자.
행렬 내 가장 큰 값으로 넣었으니 안심하고 비교해서 작거나 같을 때 넣으면 되겠다.

제일 마지막에 다시 시작점으로 돌아온 부분만 한 줄 더 추가!
혹시 모르니 이것도 최솟값 비교! (<- 이 부분 깜빡하고 빼먹으니, case 3~11 통과가 안됐다.ㅠ)

최종 최솟값을 answer에 push~push~baby~ 해주면 되겠다!!

최솟값 비교시 이런 방법도 있었다...

min = Math.min(min, tmp);

아무튼

(다음 풀이때는 점수있는 짤을 넣고싶다.)

profile
나그네 개발자

0개의 댓글