THE DEVLOG

scribbly.

자바스크립트 기본 알고리즘

2023.01.08 00:27:43

탐색 문제풀이

큰 수 출력하기

N(1<=N<=100)개의 정수를 입력받아, 자신의 바로 앞 수보다 큰 수만 출력하는 프로그램을 작성하세요.(첫 번째 수는 무조건 출력한다) 첫 줄에 자연수 N이 주어지고, 그 다음 줄에 N개의 정수가 입력된다. 자신의 바로 앞 수보다 큰 수만 한 줄로 출력한다.

  • 입력예제

6

7 3 9 5 6 12

  • 출력예제

7 9 6 12

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim().split("\n");

const input1 = parseInt(input[0]);

const input2 = input[1].split(" ").map(Number);

//solution함수 안에 답안을 작성하세요.

function solution(input1, input2) {
  let answer = String(input2[0]) + " ";

  for (i = 1; i < input1; i++) {
    if (input2[i] > input2[i - 1]) answer += String(input2[i]) + " ";
  }

  console.log(answer);
}

solution(input1, input2);
  • 풀이 해설

String(number)를 사용할 때 첫 문자가 S임을 명심! (일종의 생성자임)

보이는 학생

선생님이 N(1<=N<=1000)명의 학생을 일렬로 세웠습니다. 일렬로 서 있는 학생의 키가 앞에서부터 순서대로 주어질 때, 맨 앞에 서 있는 선생님이 볼 수 있는 학생의 수를 구하는 프로그램을 작성하세요. (앞에 서 있는 사람들보다 크면 보이고, 작거나 같으면 보이지 않습니다.) 첫 줄에 정수 N이 입력된다. 그 다음줄에 N명의 학생의 키가 앞에서부터 순서대로 주어진다. 선생님이 볼 수 있는 최대학생수를 출력한다.

  • 입력예제

8

130 135 148 140 145 150 150 153

  • 출력예제

5

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim().split("\n");

const input1 = parseInt(input[0]);

const input2 = input[1].split(" ").map(Number);

//solution함수 안에 답안을 작성하세요.

function solution(input1, input2) {
  let answer = 1;

  let max = 0;

  for (i = 1; i < input1; i++) {
    if (input2[i] > max) {
      max = input2[i];

      answer++;
    }
  }

  console.log(answer);
}

solution(input1, input2);
  • 풀이 해설

최댓값이 갱신될 때마다 answer를 증가시킨다.

가위 바위 보

A와 B가 N번 가위바위보 합니다. 가위, 바위, 보의 정보는 1:가위, 2:바위, 3:보로 정하겠습니다.

첫 번째 줄에 게임 횟수인 자연수 N(1<=N<=100)이 주어집니다.

두 번째 줄에는 A가 낸 가위, 바위, 보 정보가 N개 주어집니다.

세 번째 줄에는 B가 낸 가위, 바위, 보 정보가 N개 주어집니다.

A가 이기면 A, B가 이기면 B, 비기면 D가 출력됩니다.

  • 입력예제

5

2 3 3 1 3

1 1 2 2 3

  • 출력예제

A

B

A

B

D

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim().split("\n");

const input1 = parseInt(input[0]);

const input2 = input[1].split(" ").map(Number);

const input3 = input[2].split(" ").map(Number);

//solution함수 안에 답안을 작성하세요.

function solution(input1, input2, input3) {
  let answer;

  let aLst = input2;

  let bLst = input3;

  for (i = 0; i < input1; i++) {
    if (aLst[i] == bLst[i]) answer = "D";
    else if (aLst[i] == bLst[i] + 1 || (aLst[i] == 1 && bLst[i] == 3))
      answer = "A";
    else answer = "B";

    console.log(answer);
  }
}

solution(input1, input2, input3);
  • 풀이 해설

if문과 불리언을 활용할 수 있는지를 묻는 문제. 가위바위보의 규칙을 if문을 3번 쓰거나 불리언으로 정의할 수 있다.

점수계산

맞춘 문제는 1, 틀린 문제는 0으로 표시한다. 문제를 맞추면 1점을 준다. 연속으로 맞추면 1점씩 가산한다. K문제를 연속으로 맞추면 K점을 준다.

가령 아래의 입력예제를 연산하면 1 + 1 + (1+1) + (1+1+1) + 1 + (1+1) = 10점이다.

  • 입력예제

10

1 0 1 1 1 0 0 1 1 0

  • 출력예제

10

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim().split("\n");

const input1 = parseInt(input[0]);

const input2 = input[1].split(" ").map(Number);

//solution함수 안에 답안을 작성하세요.

function solution(input1, input2) {
  let answer;

  let score = input2[0];

  let adder = 0;

  for (i = 1; i < input1; i++) {
    if (input2[i] === 1) {
      score++;

      if (input2[i - 1]) {
        adder++;

        score += adder;
      } else adder = 0;
    }
  }

  answer = score;

  console.log(answer);
}

solution(input1, input2);
  • 풀이 해설

변수 adder를 선언하여 가산점을 계산. adder를 0으로 초기화하는 방법에 대해 다양한 방식이 있을 수 있다.

등수구하기

N(1<=N<=100)명의 학생의 국어점수가 입력되면 각 학생의 등수를 입력된 순서대로 출력하는 프로그램을 작성하세요. 첫 줄에 N(3<=N<=1000)이 입력되고, 두 번째 줄에 국어점수를 의미하는 N개의 정수가 입력된다. 같은 점수가 입력될 경우 높은 등수로 동일 처리한다. 즉 가장 높은 점수가 92점인데 92점이 3명 존재하면 1등이 3명이고 그 다음 학생은 4등이 된다.

  • 입력예제

5

87 89 92 100 76

  • 출력예제

4 3 2 1 5

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim().split("\n");

const input1 = parseInt(input[0]);

const input2 = input[1].split(" ").map(Number);

//solution함수 안에 답안을 작성하세요.

function solution(input1, input2) {
  let answer = "";

  let rank = input2.slice();

  rank.sort((a, b) => b - a);

  for (score of input2) {
    answer += String(rank.indexOf(score) + 1) + " ";
  }

  console.log(answer);
}

solution(input1, input2);
  • 풀이 해설

ArrayProto.sort(callback(){})을 참고하자.

본 문제의 경우 기존 배열과 새로운 배열을 '얕은 복사' 해야한다. [JavaScript] 깊은 복사, 얕은 복사

격자판 최대합

N*N의 격자판이 주어지면 각 행의 합, 각 열의 합, 두 대각선의 합 중 가 장 큰 합을 출력합

니다.

  • 입력예제

5

10 13 10 12 15

12 39 30 23 11

11 25 50 53 15

19 27 29 37 27

19 13 30 13 19

  • 출력예제

155

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const { arrayBuffer } = require("stream/consumers");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync(filePath).toString().trim().split("\r\n");

const input1 = parseInt(input[0]);

const input2 = [];

for (i = 0; i < input1; i++) {
  input2[i] = input[i + 1].split(" ").map(Number);
}

//solution함수 안에 답안을 작성하세요.

function solution(input1, input2) {
  let answer;

  let n = input1;

  let mt = input2;

  let max = 0;

  let dia1 = 0;

  let dia2 = 0;

  for (i = 0; i < n; i++) {
    let sum_row = 0;

    let sum_col = 0;

    for (j = 0; j < n; j++) {
      sum_row += mt[i][j];

      sum_col += mt[j][i];
    }

    if (sum_row > max) max = sum_row;

    if (sum_col > max) max = sum_col;

    dia1 += mt[i][i];

    dia2 += mt[4 - i][i];
  }

  if (dia1 > max) max = dia1;

  if (dia2 > max) max = dia2;

  answer = max;

  console.log(answer);
}

solution(input1, input2);
  • 풀이 해설

이중포문을 이용하여 합을 구하는 행렬 문제이다. 행렬을 입력받을 때부터 어떻게 split을 할지 고민하여 행렬을 제작하자. 일반적으로 행렬은 mt[행][열]의 구조를 띄게 된다.

if문이 사용된 부분은 Math.max()메서드를 이용하여 max = Math.max(max, sumRow, sumCol);로 표현할 수 있다.

봉우리

N*N 격자판의 숫자 중 자신의 상하좌우 숫자보다 큰 숫자는 봉우리 지역입니다. 봉우리 지역이 몇 개 있는 지 알아내는 프로그램을 작성하세요. 격자의 가장자리는 0으로 초기화 되었다고 가정한다. 만약 N=5 이고, 격자판의 숫자가 다음과 같다면 봉우리의 개수는 10개입니다.

0 0 0 0 0 0 0

0 5 3 7 2 3 0

0 3 7 1 6 1 0

0 7 2 5 3 4 0

0 4 3 6 4 1 0

0 8 7 3 5 2 0

0 0 0 0 0 0 0

  • 입력예제

5

5 3 7 2 3

3 7 1 6 1

7 2 5 3 4

4 3 6 4 1

8 7 3 5 2

  • 출력예제

10

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim().split("\n");

const input1 = parseInt(input[0]);

const input2 = [];

for (i = 0; i < input1; i++) {
  input2[i] = input[i + 1].split(" ").map(Number);
}

//solution함수 안에 답안을 작성하세요.

function solution(input1, input2) {
  let answer;

  let dx = [0, 0, -1, 1];

  let dy = [1, -1, 0, 0];

  let counter = 25;

  for (let y = 0; y < input1; y++) {
    for (let x = 0; x < input1; x++) {
      for (let i = 0; i < 4; i++) {
        if (
          x + dx[i] < 0 ||
          x + dx[i] >= input1 ||
          y + dy[i] < 0 ||
          y + dy[i] >= input1
        )
          continue;

        if (input2[x + dx[i]][y + dy[i]] >= input2[x][y]) {
          counter--;

          break;
        }
      }
    }
  }

  answer = counter;

  console.log(answer);
}

solution(input1, input2);
  • 풀이 해설

행렬의 벡터값 dx, dy을 활용한 구현 문제이다. 좌표가 (0,0)인 (x, y)의 상, 하, 좌, 우의 각 좌표 (dx, dy)는 (0,-1)(0,1)(-1,0)(1,0)이다.

이를 표로 만들면 다음과 같다.


const  dx = [0, 0, -1, 1]

const  dy = [-1, 1, 0, 0]

for(i=0; i<4; 1++) {

console.log(`(${dx[i]}, ${dy[i]})`)

}

i 인덱스가 순회하는 동안 벡터는 상, 하, 좌, 우를 탐색하게 된다. 해당 벡터값을 이중for문과 결합하게 된다.


문자열 탐색

회문 문자열

회문이면 YES, 회문이 아니면 NO를 출력하라.

  • 입력예제

gooG

  • 출력예제

YES

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim();

//solution함수 안에 답안을 작성하세요.

function solution(input) {
  let answer = "YES";

  let str = input.toLowerCase();

  for (i = 0; i < parseInt(str.length) / 2; i++) {
    if (str[i] !== str[str.length - 1 - i]) {
      answer = "NO";

      break;
    }
  }

  console.log(answer);
}

solution(input);
  • 풀이 해설

펠린드롬 문제이다. 투포인터를 이용해 풀이하였다. 유의할 점은 StringProto.toLowerCase()는 리턴값을 받아줄 변수가 필요하다는 점이다. 본 풀이에서는 str로 input.toLowerCase()의 리턴값을 받아 풀이하였다.

유효한 팰린드롬

문자열이 앞에서 읽을때나 뒤에서 읽을 때나 같은 팰린드롬이면 YES, 아니면 NO를 출력하라.

알파벳 이외의 글자는 무시하며, 대소문자를 구분하지 않는다.

  • 입력예제

found7, time: study; Yduts; emit, 7Dnuof

  • 출력예제

YES

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim();

//solution함수 안에 답안을 작성하세요.

function solution(input) {
  let answer = "YES";

  let str = input.toLowerCase().replace(/[^a-z]/g, "");

  if (str !== str.split("").reverse().join("")) answer = "NO";

  console.log(answer);
}

solution(input);
  • 풀이 해설

팰린드롬을 reverse를 이용해 풀었다.

StringProto.replace('찾을 문자', '바꿀 문자') : 찾을 문자에 정규표현식이 들어갈 수 있다.

정규표현식(RegExp) 정규표현식의 개념과 패턴 사용법 총정리 [JavaScript] replace(치환) 및 정규식 RegExp | PoiemaWeb [JS] 📚 정규식 (RegExp) - 누구나 이해하기 쉽게 정리

  • 정규표현식을 사용할 때에는 표현식 앞, 뒤로 /를 감싼다.

  • [/^표현식/] : 해당 표현식에 해당하지 않는 것을 반환한다.

  • 플래그 [/표현식/igm] : 표현식 뒤에 i, g, m의 표현식을 사용할 수 있다.

    • i : Ignore Case - 대소문자 무관하게 탐색한다.
  • g : Global - 문자열 전역을 검사합니다. g가 없으면 최초 검색결과만 만환합니다.

  • m : multiline - 문자열이 여러줄로 적혀있는 경우 여러줄 모두를 검색합니다.

숫자만 추출

문자와 숫자가 섞여있는 문자열이 주어지면 그 중 숫자만 추출하여 그 순서대로 자연수를 만

듭니다.

  • 입력예제

g0en2T0s8eSoft

  • 출력예제

208

  • 답안
//인풋을 입력받습니다.

const fs = require("fs");

const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";

const input = fs.readFileSync("input.txt").toString().trim();

//solution함수 안에 답안을 작성하세요.

function solution(input) {
  let answer = "YES";

  let str = input.toLowerCase().replace(/[^\d]/g, "");

  answer = parseInt(str);

  console.log(answer);
}

solution(input);
  • 풀이 해설

정규표현식 \d는 digital number를 의미한다.

가장 짧은 문자거리

한 개의 문자열 s와 문자 t가 주어지면 문자열 s의 각 문자가 문자 t와 떨어진 최소거리를 출력하는 프로그램을 작성하세요.

  • 입력예제

teachermode e

  • 출력예제

1 0 1 2 1 0 1 2 2 1 0

  • 답안
//인풋을 입력받습니다.
const fs = require("fs");
const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";
const input = fs.readFileSync("input.txt").toString().trim().split(" ");
const s = input[0];
const t = input[1];

//solution함수 안에 답안을 작성하세요.
function solution(s, t) {
  let answer = [];
  let distance = Number.MAX_SAFE_INTEGER;

  //앞에서 부터 탐색
  for (c of s) {
    if (c === t) {
      distance = 0;
      answer.push(distance);
    } else {
      answer.push(++distance);
    }
  }

  //거꾸로 탐색하는 방법
  distance = Number.MAX_SAFE_INTEGER;
  for (i = s.length - 1; i >= 0; i--) {
    if (s[i] === t) distance = 0;
    else {
      Math.min(++distance, answer[i]);
    }
  }

  console.log(answer);
}
solution(s, t);
  • 풀이 해설
    부분합을 이용한 문제

문자열 압축

같은 문자가 연속으로 반복되는 경우 반복되는 문자 바로 오른쪽에 반복 횟수를 표기하는 방법으로 문자열을 압축. 단 반복횟수가 1인 경우 생략한다.

  • 입력예제

KKHSSSSSSSE

  • 출력예제

K2HS7E

  • 답안
//인풋을 입력받습니다.
const fs = require("fs");
const filePath =
  process.platform === "linux" ? "/dev/stdin" : __dirname + "/input.txt";
const input = fs.readFileSync("input.txt").toString().trim();

//solution함수 안에 답안을 작성하세요.
function solution(s) {
  let answer = s[0];
  let cnt = 1;
  for (i = 1; i < s.length; i++) {
    if (s[i] === s[i - 1]) cnt++;
    else {
      if (cnt > 1) answer += String(cnt);
      cnt = 1;
      answer += s[i];
    }
  }

  console.log(answer);
}
solution(input);
  • 풀이 해설
    절차가 중요. answer의 초깃값을 무엇으로 두는지, cnt를 언제 answer로 넘겨주는지 등을 꼼꼼히 체크하며 진행할 것.
    cnt가 1인 경우 생략하도록 문제에서 요구하는데, 이 경우는 그냥 if문으로 예외처리 하는 것이 편함