The journey to becoming a developer

My future is created by what I do today, not tomorrow.

Algorithms/Programmers

[프로그래머스 Level 1] 직사각형 별찍기 (자바스크립트)

Millie 2021. 10. 5. 11:46

Description

※ Use Standrad input and output to solve this challenge

Print a n by m grid of asterisks.

Constraints

The first line contains 2-separated integers, n and m.

  • 1 ≤ n, m ≤ 1,000

나의 풀이

이 문제는 보자마자 "중첩 for문으로 풀어야겠다"라는 생각이 들었다. 

process.stdin.setEncoding('utf8');
process.stdin.on('data', data => {
    const n = data.split("");
    const a = Number(n[0]), b = Number(n[1]);
    let star = ''
    for(let i = 0; i < b; i++) {
        for(let j = 0; j < a; j++) {
            star += '*'
        }
        star += '\n'
    }
    console.log(star);
});

우선 standard input & output부터 살펴보자.

  1. 입력받은 숫자 두 개는 data에 문자열 타입으로 받아지게 된다. 예를 들어 가로는 5, 세로는 3인 직사각형 별을 찍고 싶다면 "53"이라는 입력이 data에 들어갈 것이다. 
  2. 그 후 이 data를 split('')으로 하나씩 분리해 배열로 변경해준다. split 메서드는 string에 쓰일 수 있는데, 구분자(separator)를 명시해 주면 끊어야 할 위치를 알려 주게 된다. 구분자는 빈 문자열이어서 ["5", "3"] 이런 식으로 쪼개지게 된다.
  3. 배열에 있는 요소들을 인덱스 0, 1로 접근해서 각각 Number로 형 변환을 해 준다. 그러면 결국 a = 5, b = 3 이런 식으로 할당되게 된다. a는 가로의 길이, b는 세로의 길이이다. 

이제 입력받은 가로의 길이(a)와 세로의 길이(b)를 토대로 별을 찍어 보자. 

  1. 가로의 길이만큼의 별을 찍고, 그것을 세로의 길이만큼 반복하면 된다. 
  2. 세로의 길이만큼 반복할 때는 줄바꿈 기호를 넣어서 한 줄로 출력되지 않도록 한다. 

다른 방법

이중 for문이 아닌, 메서드를 사용하는 방법으로도 문제를 풀 수 있다. 세 가지 다른 풀이를 참고해 보았다.

1. repeat 활용하기

process.stdin.setEncoding('utf8');
process.stdin.on('data', data => {
  const n = data.split(' ');
  const a = Number(n[0]),b = Number(n[1]);
  let row = '*'.repeat(a);
  for (let i = 0; i < b; i++) {
    console.log(row);
  }
});

받아온 a의 값을 토대로 가로줄 한 줄을 만들 때, for문이 아닌 repeat으로 row를 만든다.

그 후 b의 값을 토대로 세로 줄을 만들 때는 for문을 돌려서 row를 반복한다. 이때 줄바꿈 기호를 같이 넣어준다.

process.stdin.setEncoding('utf8');
process.stdin.on('data', data => {
    const n = data.split(" ");
    const a = Number(n[0]), b = Number(n[1]);
    const star = `${'*'.repeat(a)}\n`;
    console.log(star.repeat(b));
});

위의 풀이도 repeat을 썼는데, 추가적으로 template literals와 줄바꿈 기호도 활용했다.

별찍기를 할 때 template literals를 활용할 생각을 잘 못했는데, 기발한 풀이라고 생각했다.

2. Array(n), fill, join 활용하기

process.stdin.setEncoding('utf8');
process.stdin.on('data', data => {
  const n = data.split(' ');
  const a = Number(n[0]), b = Number(n[1]);
  console.log(Array(b).fill(Array(a).fill('*').join('')).join('\n'));
});

내부에 있는 Array(a).fill('*').join('')을 보면, Array() constructor를 이용해서 우선 a 길이만큼의 array를 만든 후, 각 요소를 * 하나로 채운 후 join으로 하나의 문자열로 합친다. 이렇게 하면 하나의 row가 완성된다.

같은 방식으로 b 길이만큼의 Array를 만들고, 각 요소마다 row를 채워준 후, join을 할 때는 줄바꿈을 해 준다.

3. Array.from, map 활용하기 

const solution = (a, b) =>
  new Array(b) 
    .fill([]) 
    .map(() => Array.from(Array(a), () => '*').join(''))
    .join('\n');

Array.from은 이런 식으로 사용한다.

이런 식으로 어떤 배열을 생성한 후 각 요소를 *로 지정하는 식으로 Array.from을 활용할 수 있다.

이렇게 a길이의 row를 생성한다.

그런데 사실 이 풀이에서 map을 없애도 답은 같다. fill로 각 열을 채워주기 때문이다.

const solution = (a, b) =>
  new Array(b) 
    .fill(Array.from(Array(a), () => '*').join(''))
    .join('\n');

이렇게 좀 더 간결하게 풀 수 있다. 사실상 2번의 풀이와 거의 동일하다.


별을 찍을 때 전통적인 이중 for문으로 풀 수도 있지만 다른 사람들의 풀이를 보며 메서드를 이용할 수 있다는 것을 배운 알찬 시간이었다.