문제

https://www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

접근

1. DFS -> time over

2. BFS 

풀이

take-1: 실패 (10)

- [0,3] 큐를 마지막으로 반복문이 멈췄다. 

- idxPairs 까지는 뽑히는데 validPairs 에서 아무것도 검출되지 않았다. -> nx, ny 범위조건을 둘다 N 으로 해놨었다.

const solution = (input) => {
  const [N, M] = input.shift().split(" ").map(Number);
  const graph = [...input].map((v) => v.split("").map(Number));
  let answer = Number.MIN_SAFE_INTEGER;

  const inValidRange = (pair) => {
    const [nx, ny] = pair;
    if (nx < 0 || ny < 0 || nx >= N || ny >= N) return false;
    else if (graph[nx][ny] === 1) return true;
    return false;
  };

  const bfs = (row, col) => {
    const queue = [[row, col]];
    const seen = new Array(N).fill(0).map(() => new Array(N).fill(false));
    seen[row][col] = true;
    let cnt = 1;

    while (queue.length) {
      const [x, y] = queue.shift();
      graph[x][y] = 0;
      const idxPairs = [
        [x - 1, y],
        [x, y + 1],
        [x + 1, y],
        [x, y + 1],
      ];
      const validIdxPairs = idxPairs.filter((v) => inValidRange(v));

      for (let idxPair of validIdxPairs) {
        const [nx, ny] = idxPair;
        if (graph[nx][ny] === 1 && !seen[nx][ny]) {
          seen[nx][ny] = true;
          cnt++;
          console.log("nx,ny: ", nx, ny, "\n", "cnt: ", cnt, "queue: ", queue);
          queue.push([nx, ny]);
        }
      }
    }
    return cnt;
  };

  const count = bfs(0, 0);
  answer = answer < count ? count : answer;

  return answer;
};

console.log(solution(input));

take - 2: fail (17)

const solution = (input) => {
  const [N, M] = input.shift().split(" ").map(Number);
  const graph = [...input].map((v) => v.split("").map(Number));
  let answer = Number.MIN_SAFE_INTEGER;

  const inValidRange = (pair) => {
    const [nx, ny] = pair;
    if (nx < 0 || ny < 0 || nx >= N || ny >= M) return false;
    if (graph[nx][ny] === 1) return true;
    return false;
  };

  const bfs = (row, col) => {
    const queue = [[row, col]];
    const seen = new Array(N).fill(0).map(() => new Array(M).fill(false));
    seen[row][col] = true;
    let cnt = 1;

    while (queue.length) {
      const [x, y] = queue.shift();
      graph[x][y] = 0;
      const idxPairs = [
        [x - 1, y],
        [x, y - 1],
        [x + 1, y],
        [x, y + 1],
      ];

      const validIdxPairs = idxPairs.filter((v) => inValidRange(v));
      console.log(x, y);
      console.log(idxPairs);
      console.log(validIdxPairs);

      for (let idxPair of validIdxPairs) {
        const [nx, ny] = idxPair;
        if (graph[nx][ny] === 1 && !seen[nx][ny]) {
          seen[nx][ny] = true;
          cnt++;
          queue.push([nx, ny]);
        }
      }
      console.log("queue: ", queue);
    }
    return cnt;
  };

  const count = bfs(0, 0);
  answer = answer < count ? count : answer;
  return answer;
};

console.log(solution(input));

 

tial-3: success!!

const solution = (input) => {
  const [N, M] = input.shift().split(" ").map(Number);
  const graph = [...input].map((v) => v.split("").map(Number));
  let answer = Number.MIN_SAFE_INTEGER;

  const inValidRange = (pair) => {
    const [nx, ny] = pair;
    if (nx < 0 || ny < 0 || nx >= N || ny >= M) return false;
    if (graph[nx][ny] === 1) return true;
    return false;
  };

  const bfs = (row, col) => {
    const queue = [[row, col]];
    const seen = new Array(N).fill(0).map(() => new Array(M).fill(0));
    seen[row][col] = 1;

    while (queue.length) {
      const [x, y] = queue.shift();
      graph[x][y] = 0;
      const idxPairs = [
        [x - 1, y],
        [x, y - 1],
        [x + 1, y],
        [x, y + 1],
      ];

      const validIdxPairs = idxPairs.filter((v) => inValidRange(v));
      console.log(x, y);
      console.log(idxPairs);
      console.log(validIdxPairs);

      for (let idxPair of validIdxPairs) {
        const [nx, ny] = idxPair;
        if (graph[nx][ny] === 1 && !seen[nx][ny]) {
          seen[nx][ny] = seen[x][y] + 1;
          queue.push([nx, ny]);
        }
      }
      console.log("queue: ", queue);
    }
    return seen[N - 1][M - 1];
  };

  const count = bfs(0, 0);
  answer = answer < count ? count : answer;
  return answer;
};

console.log(solution(input));

문제

https://www.acmicpc.net/problem/2667

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여

www.acmicpc.net

접근

 

풀이

// 공통 상단 코드
// 백준 제출시
// const address="/dev/stdin"

// VSC 테스트시
const address = "./input.txt";
const input = require("fs")
  .readFileSync(address)
  .toString()
  .trim()
  .split("\n")
  .map((v) => v.split("").map(Number));

 

시도 1

결과: 실패

3,9,7,11

로 나옴 (답은 3,7,8,9)

seen(visited) 에 뭔가 중복이 있을 거라 생각하고 봤더니

이렇게 [1,2] 처럼 중복되어 있는 몇 배열들이 보인다.

Set()은 중복값이 안되는 걸로 알았는데 object 는 배열로 안치나보다. 

const solution = (input) => {
  const [N, ...graph] = input;
  let numOfComplex = 0;
  const houses = [];

  const filter = (pair) => {
    const [nx, ny] = pair;
    if (nx < 0 || ny < 0 || nx >= N || ny >= N) return false;
    else if (graph[nx][ny] === 1) return true;
    return false;
  };

  const bfs = (row, col) => {
    const seen = new Set();
    const queue = [[row, col]];
    seen.add([row, col]);
    let house = 0;
    console.log(`queue (${row}, ${col}): `, queue, "\n");

    while (queue.length) {
      const [x, y] = queue.shift();
      console.log("shifted: ", [x, y]);
      console.log("seen: ", seen);
      console.log("queue after loop: ", queue);
      graph[x][y] = 0;
      const idxPairs = [
        [x - 1, y],
        [x, y + 1],
        [x + 1, y],
        [x, y - 1],
      ];
      const validIdxPairs = idxPairs.filter((idx) => filter(idx));
      console.log("valid pairs:", validIdxPairs, "\n");
      for (const idxPair of validIdxPairs) {
        const [nx, ny] = idxPair;
        if (graph[nx][ny] === 1 && !seen.has([nx, ny])) {
          seen.add([nx, ny]);
          house++;
          queue.push([nx, ny]);
        }
      }
    }

    houses.push(house);
  };

  for (let i = 0; i < N; i++) {
    for (let j = 0; j < N; j++) {
      if (graph[i][j] === 1) {
        numOfComplex++;
        bfs(i, j);
      }
    }
  }

  const answer = [numOfComplex, ...houses];
  return answer.join("\n");
};

console.log(solution(input));

시도2

수정사항:

- seen set -> arr

- house++ 새 라운드 시작할 때도 실행

- 인풋 받을 때 "\n" 까지만 받고 일일이 할당. 구조분해 x. 

 

결과: 실패

콘솔에는 답으로 뜨나 백준 제출시 "틀렸습니다"

const solution = (input) => {
  const N = +input.shift();
  const graph = input;
  let numOfComplex = 0;
  const houses = [];

  const filter = (pair) => {
    const [nx, ny] = pair;
    if (nx < 0 || ny < 0 || nx >= N || ny >= N) return false;
    else if (graph[nx][ny] === 1) return true;
    return false;
  };

  const bfs = (row, col) => {
    const seen = new Array(N).fill(0).map(() => new Array(N).fill(false));
    const queue = [[row, col]];
    let house = 0;
    seen[row][col] = true;
    house++;

    while (queue.length) {
      const [x, y] = queue.shift();
      graph[x][y] = 0;
      const idxPairs = [
        [x - 1, y],
        [x, y + 1],
        [x + 1, y],
        [x, y - 1],
      ];
      const validIdxPairs = idxPairs.filter((idx) => filter(idx));
      for (const idxPair of validIdxPairs) {
        const [nx, ny] = idxPair;
        if (graph[nx][ny] === 1 && !seen[nx][ny]) {
          seen[nx][ny] = true;
          house++;
          queue.push([nx, ny]);
        }
      }
    }

    houses.push(house);
  };

  for (let i = 0; i < N; i++) {
    for (let j = 0; j < N; j++) {
      if (graph[i][j] === 1) {
        numOfComplex++;
        bfs(i, j);
      }
    }
  }

  const answer = [numOfComplex, ...houses];
  return answer.join("\n");
};

console.log(solution(input));

 

'Board > 알고리즘' 카테고리의 다른 글

백준 10828 자바스크립트  (0) 2023.01.31
백준 2178 미로 찾기  (0) 2023.01.28
백준 2606 자바스크립트  (0) 2023.01.26
백준 2468 자바스크립트  (0) 2023.01.25
백준 2178 자바스크립트  (0) 2023.01.24

문제

https://www.acmicpc.net/problem/2606

 

2606번: 바이러스

첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어

www.acmicpc.net

접근 

기본적인 그래프 탐색 문제. 

연결된 노드가 몇 개인지를 구하는.

 

단, 맨 처음 노드 시작을 인덱스 0이 아닌 1로 시작해줘야 한다.

풀이

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

function solution(input) {
  const N = +input.shift(); // 노드 수
  const M = +input.shift(); // 간선 수
  const edges = input.map((v) => v.split(" ").map(Number));

  // 그래프 그리기
  const vertices = Array(N + 1)
    .fill(0)
    .map(() => []);
  for (let edge of edges) {
    const [v0, v1] = edge;
    vertices[v0].push(v1);
    vertices[v1].push(v0);
  }

  // 실행
  const seen = new Set();
  let count = 0;
  const dfs = (start) => {
    for (let end of vertices[start]) {
      if (!seen.has(end)) {
        seen.add(end);
        count++;
        dfs(end);
      }
    }
  };
  seen.add(1);
  dfs(1);
  console.log(seen);
  return count;
}

console.log(solution(input));

참조: https://www.acmicpc.net/source/54379165

 

로그인

 

www.acmicpc.net

 

'Board > 알고리즘' 카테고리의 다른 글

백준 2178 미로 찾기  (0) 2023.01.28
백준 2667 단지 찾기 자바스크립트  (0) 2023.01.27
백준 2468 자바스크립트  (0) 2023.01.25
백준 2178 자바스크립트  (0) 2023.01.24
백준 2667 자바스크립트  (0) 2023.01.24

문제

https://www.acmicpc.net/problem/2468

 

2468번: 안전 영역

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는

www.acmicpc.net

 

접근 

- N보다 큰 수가 있는 부분을 탐색하고, 한 부분의 탐색이 끝날 때 cnt++ 을 한다. cnt 최댓값을 구한다. 

- 결과: 중도포기

 

풀이

// 백준 제출시
// const address="/dev/stdin"

// VSC 테스트시
const address = "./input.txt";
const input = require("fs").readFileSync(address).toString().trim().split("\n");

const N = +input[0];
const areas = input.slice(1).map((v) => v.split(" ").map((v) => +v));

const offsetX = [0, 0, -1, 1];
const offsetY = [-1, 1, 0, 0];

const dfs = (x, y, height, visited) => {
  offsetX.forEach((dx, i) => {
    const nx = x + dx;
    const ny = y + offsetY[i];
    if (nx >= 0 && nx < N && ny >= 0 && ny < N && !visited[nx][ny]) {
      visited[nx][ny] = true;
      dfs(nx, ny, height, visited);
    }
  });
};

let maxCount = 0;
for (let height = 0; height <= 100; height++) {
  let count = 0;
  const visited = [...Array(N)].map((_, x) =>
    [...Array(N)].map((_, y) => areas[x][y] <= height)
  );
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < N; j++) {
      if (!visited[i][j]) {
        visited[i][j] = true;
        dfs(i, j, height, visited);
        count++;
      }
    }
  }
  maxCount = Math.max(maxCount, count);
}

console.log(maxCount);

출처(https://tesseractjh.tistory.com/188)

'Board > 알고리즘' 카테고리의 다른 글

백준 2667 단지 찾기 자바스크립트  (0) 2023.01.27
백준 2606 자바스크립트  (0) 2023.01.26
백준 2178 자바스크립트  (0) 2023.01.24
백준 2667 자바스크립트  (0) 2023.01.24
백준 14888 자바스크립트  (0) 2023.01.22

문제

https://www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

 

접근

 

 두 정수 N, M(2 ≤ N, M ≤ 100) 으로 완전탐색을 해도 무방하다.

 

DFS:

D(0,0) -> D

 

1. 백트래킹을 어떻게 하지?

visited 이용

2. 행과 열의 크기가 다를 때 도착지점 설정

더 긴 쪽만큼 순환

3. case3 통과 x

각각의 수들은 붙어서 입력으로 주어진다. <- 이 부분을 주의해서 N,M,graph 입력을 수정해줬더니 해결.

4. 시간 초과...

-> BFS 로 풀어보자.

 

풀이

'Board > 알고리즘' 카테고리의 다른 글

백준 2606 자바스크립트  (0) 2023.01.26
백준 2468 자바스크립트  (0) 2023.01.25
백준 2667 자바스크립트  (0) 2023.01.24
백준 14888 자바스크립트  (0) 2023.01.22
백준 2661 자바스크립트  (0) 2023.01.21

풀이 참조

인프런 강의 그래프 탐색 - 섬나라 아일랜드 문제와 비슷하여 이를 참고했다.

같은 문제 dfs vs bfs 접근 비교

 

 

'Board > 알고리즘' 카테고리의 다른 글

백준 2468 자바스크립트  (0) 2023.01.25
백준 2178 자바스크립트  (0) 2023.01.24
백준 14888 자바스크립트  (0) 2023.01.22
백준 2661 자바스크립트  (0) 2023.01.21
백준 14889 자바스크립트  (0) 2023.01.19

문제

https://www.acmicpc.net/problem/14888

 

14888번: 연산자 끼워넣기

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 

www.acmicpc.net

N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 N-1개의 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다.

 

식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.

  • 1+2+3-4×5÷6 = 1
  • 1÷2+3+4-5×6 = 12
  • 1+2÷3×4-5+6 = 5
  • 1÷2×3-4+5+6 = 7

N개의 수N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.

 

접근

3    //N
3 4 5 // 수열
1 0 1 0 // 각각 +,-,*,/ 연산자의 갯수

이라면

만들 수 있는 식

3+4*5 = 35

3*4+5 = 17

 

- 첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 이므로 -> 완전탐색 

- 수열은 이미 주어졌으니 따로 구할 필요 x

- 연산자의 순서에 따라 값이 달라지니 순열(permutation) 문제겠구나.

-- 1. 들어온 수열과 연산자를 각각 다른 배열에 넣는다. 

-- 2. 수열.join("연산자")로 반복문을 돌린다.

--- 2-1.결과를 array 에 푸시한다. 

--- 2-2.연산자 배열의 위치를 바꾼다.

-- 3. 결과 배열에서 가장 작은 수와 가장 큰 수를 찾아 리턴한다.

 

1. 들어온 수열과 연산자를 각각 다른 배열에 넣는다. 

const input = require("fs")
  .readFileSync(address)
  .toString()
  .trim()
  .split("\n")
  .map((v) => v.split(" ").map(Number));

function getOperations(arr) {
  const operations = ["+", "-", "*", "/"];

  operations.forEach((v, idx) => {
    let amount = arr[idx];
    for (let j = 0; j < amount; j++) {
      operations.push(operations[idx]);
    }
  });

  return operations;
}

function solution(input) {
  const [N, A, amount] = input;
  const operations = getOperations(amount);

  return operations;
}

 

 2-1. 재귀를 이용해 결과를 array 에 푸시한다.

// 백준 제출시
// const address="/dev/stdin"

// VSC 테스트시
const address = "./input.txt";

const input = require("fs")
  .readFileSync(address)
  .toString()
  .trim()
  .split("\n")
  .map((v) => v.split(" ").map(Number));

const getOperations = (arr) => {
  const operations = ["+", "-", "*", "/"];

  operations.forEach((v, idx) => {
    let amount = arr[idx];
    for (let j = 0; j < amount; j++) {
      operations.push(operations[idx]);
    }
  });

  return operations;
};

function solution(input) {
  const [N, A, amount] = input;
  const operations = getOperations(amount);

  const results = [];
  let result = Number.MAX_SAFE_INTEGER;
  let check = Array(N).fill(0);

  const recursion = (idx) => {
    if (idx === N - 1) return;
    const copy = [...A];
    let tmpOp = operations.slice(0, 2);
    copy.splice(idx + 1, 0, tmpOp[0]);
    copy.splice(N, 0, tmpOp[1]);
    let tmp = operations.shift();
    operations.push(tmp);
    const test = eval(copy.join(""));
    results.push(test);
  };

  recursion(0);

  let min = Math.min(...results);
  let max = Math.max(...results);
  let answer = `${min}\n${max}`;

  return answer;
}

console.log(solution(input));

 

2-2.연산자 배열의 위치를 바꾼다.

const changeArrayOrder = function(list, targetIdx, moveValue) {
  // 배열값이 없는 경우 나가기
  if (list.length < 0) return;

  // 이동할 index 값을 변수에 선언
  const newPosition = targetIdx + moveValue;

  // 이동할 값이 0보다 작거나 최대값을 벗어나는 경우 종료
  if (newPosition < 0 || newPosition >= list.length) return;

  // 임의의 변수를 하나 만들고 배열 값 저장
  const tempList = JSON.parse(JSON.stringify(list));

  // 옮길 대상을 target 변수에 저장하기
  const target = tempList.splice(targetIdx, 1)[0];

  // 새로운 위치에 옮길 대상을 추가하기
  tempList.splice(newPosition, 0, target);
  return tempList;
};

 

풀이

시도 끝에 결국 실패. 여전히 재귀로 구현하는 것은 아직 어렵다.

// 백준 제출시
// const address="/dev/stdin"

// VSC 테스트시
const address = "./input.txt";

const input = require("fs")
  .readFileSync(address)
  .toString()
  .trim()
  .split("\n")
  .map((v) => v.split(" ").map(Number));

const getOperations = (arr) => {
  const operations = ["+", "-", "*", "/"];

  operations.forEach((v, idx) => {
    let amount = arr[idx];
    for (let j = 0; j < amount; j++) {
      operations.push(operations[idx]);
    }
  });

  return operations;
};

function solution(input) {
  const [N, A, amount] = input;
  const operations = getOperations(amount);

  const results = [];
  let result = Number.MAX_SAFE_INTEGER;
  let check = Array(N).fill(0);

  const recursion = (idx) => {
    if (idx === N - 1) return;
    const copy = [...A];
    let tmpOp = operations.slice(0, 2);
    copy.splice(idx + 1, 0, tmpOp[0]);
    copy.splice(N, 0, tmpOp[1]);
    let tmp = operations.shift();
    operations.push(tmp);
    const test = eval(copy.join(""));
    results.push(test);
  };

  recursion(0);

  let min = Math.min(...results);
  let max = Math.max(...results);
  let answer = `${min}\n${max}`;

  return answer;
}

console.log(solution(input));

 


참조풀이

https://gobae.tistory.com/49

https://junghyeonsu.tistory.com/196

 

'Board > 알고리즘' 카테고리의 다른 글

백준 2178 자바스크립트  (0) 2023.01.24
백준 2667 자바스크립트  (0) 2023.01.24
백준 2661 자바스크립트  (0) 2023.01.21
백준 14889 자바스크립트  (0) 2023.01.19
[알고리즘 공부] 20230115 2주차 회고  (0) 2023.01.16

문제

https://www.acmicpc.net/problem/2661

 

2661번: 좋은수열

첫 번째 줄에 1, 2, 3으로만 이루어져 있는 길이가 N인 좋은 수열들 중에서 가장 작은 수를 나타내는 수열만 출력한다. 수열을 이루는 1, 2, 3들 사이에는 빈칸을 두지 않는다.

www.acmicpc.net

1,2,3 으로만 이루어진 N자리 숫자를 만든다. 이 중 가장 작은 수를 리턴한다.

단, 같은 순서가 연속해서 반복될 수 없다. ex) 33, 123123321

 

접근

- 12131213 처럼 딱히 규칙이 있지도 않고고, 1 <= N <= 80 으로 범위가 큰 수가 아니므로 완전탐색이 가능하다.

- 우선 수열이 좋은 수열인지(같은 순서가 연속해서 반복되지 않는지) 판단해야 한다. 해당 블로그를 참조하였다.

1211 => 길이 4, 1자리 비교, 나쁜 수열

1212 => 길이 4, 1자리 비교, 좋은 수열
1212 => 길이 4, 2자리 비교, 나쁜 수열

123123 => 길이 6, 1자리 비교, 좋은 수열
123123 => 길이 6, 2자리 비교, 좋은 수열
123123 => 길이 6, 3자리 비교, 나쁜 수열

- 해당 접근 방식을 코드로 짠다. 재귀를 이용해 전체 탐색을 했다.

 

 

 

시도

1차 시도

결과: 틀렸습니다

// 백준 제출시
// const address="/dev/stdin"

// VSC 테스트시
const address = "./input.txt";
const input = require("fs").readFileSync(address).toString().trim().split("\n");

const solution = (input) => {
  const N = +input;
  let stop = false;
  let min = Number.MAX_SAFE_INTEGER;

  const isGoodSequence = (str) => {
    let len = str.length;
    let loop = len / 2;
    let start = len - 1;
    let end = len;

    for (let i = 1; i <= loop; i++) {
      if (str.substring(start - i, end - i) === str.substring(start, end))
        return false;
      start -= 1;
    }

    return true;
  };

  const recursion = (len, str) => {
    if (stop) return;
    if (len === N) {
      stop = true;
      console.log(str);
      min = min > Number(str) ? Number(str) : min;
    }
    // 수열은 1,2,3 중 하나로 이루어져 있다.
    for (let i = 1; i <= 3; i++) {
      if (isGoodSequence(str + i)) recursion(len + 1, str + i);
    }
  };

  // 가장 작은 수를 구하는 것이므로 첫번째 자리는 항상 "1"이 되어야하고, 따라서 따로 탐색할 필요 x
  recursion(1, "1");

  return min;
};

console.log(solution(input));

 

2차 시도

결과: 맞았습니다!!

const address="/dev/stdin"
const input = require("fs").readFileSync(address).toString().trim().split("\n");

const solution = (input) => {
  const N = +input;
  let stop = false;

  const isGoodSequence = (str) => {
    let len = str.length;
    let loop = len / 2;
    let start = len - 1;
    let end = len;

    for (let i = 1; i <= loop; i++) {
      if (str.substring(start - i, end - i) === str.substring(start, end))
        return false;
      start -= 1;
    }

    return true;
  };

  const recursion = (len, str) => {
    if (stop) return;
    if (len === N) {
      stop = true;
      console.log(str);
    }
    // 수열은 1,2,3 중 하나로 이루어져 있다.
    for (let i = 1; i <= 3; i++) {
      if (isGoodSequence(str + i)) recursion(len + 1, str + i);
    }
  };

  // 가장 작은 수를 구하는 것이므로 첫번째 자리는 항상 "1"이 되어야하고, 따라서 따로 탐색할 필요 x
  recursion(1, "1");
};

solution(input);

 

 

분석

왜 min 부분을 삭제하니 통과한 걸까?

 우선 굳이 min 이 필요 없었다. 차례대로 작은수부터 대입하니까 반복문이 끝나기전 제일 먼저이자 마지막으로 찍힌 수가 어차피 가장 작은 수이기 때문이다.

 1차 풀이도 틀리지는 않았는데 틀렸던 이유는 정답(min)의 출력타입이 number 였기 때문이다. 정답으로 제출한 코드 마지막 부분만 console.log(Number(string)) 으로 쳤더니 틀렸다고 나온다. 출력 타입도 str 이어야 하는 구나.

 

나보다 속도가 적게 나온 다른 사람 코드 분석

1. 좋은 수열인지 판별하는 함수에서 substring 메소드가 아닌 slice 메서드를 사용

2. 재귀 함수에서 정답을 도출할 때 string 대신 array 를 사용

3. 재귀 함수에서 백트래킹시 조건문을 좋은 수열일 경우에만 진행이 아닌 나쁜 수열일 경우 반복문을 패스하도록 설정

const fs = require('fs');
// /dev/stdin
const input = fs.readFileSync("/dev/stdin").toString().trim().split("\n").map((v)=> v.split(" ").map((v)=> parseInt(v)))


// 숫자 1, 2, 3으로만 이루어지는 수열이 있다. 
// 임의의 길이의 인접한 두 개의 부분 수열이 동일한 것이 있으면, 
// 그 수열을 나쁜 수열이라고 부른다. 그렇지 않은 수열은 좋은 수열이다.
// 첫 번째 줄에 1, 2, 3으로만 이루어져 있는 길이가 N인 좋은 수열들 중에서 가장 작은 수를 나타내는 수열만 출력한다.

function solution (N){
    const arr = [1,2,3]
    const result = []
    const dfs = (depth, number = '') => {
        if(result.length > 0) return
        if (depth === N) {
            result.push(number)
            return
        }
        for(let i = 0; i < arr.length; i++) {
            const nextArray = number + arr[i].toString()
            if(isBad(nextArray)) continue
            dfs(depth+1, nextArray)
        }
        
    }

    dfs(0)



    return result[0]
}

function isBad (str) {
    for (let i = 1; i <= str.length/2; i++) {
        const last = str.slice(-i)
        const before = str.slice(-i*2, -i)
        if (last === before) return true
    }
    return false
}

console.log(solution(...input[0]))

 

 

 

'Board > 알고리즘' 카테고리의 다른 글

백준 2178 자바스크립트  (0) 2023.01.24
백준 2667 자바스크립트  (0) 2023.01.24
백준 14888 자바스크립트  (0) 2023.01.22
백준 14889 자바스크립트  (0) 2023.01.19
[알고리즘 공부] 20230115 2주차 회고  (0) 2023.01.16

https://www.acmicpc.net/problem/14889

 

14889번: 스타트와 링크

예제 2의 경우에 (1, 3, 6), (2, 4, 5)로 팀을 나누면 되고, 예제 3의 경우에는 (1, 2, 4, 5), (3, 6, 7, 8)로 팀을 나누면 된다.

www.acmicpc.net

 

문제 해석

주어진 n 에서 n/2 만큼 스타트팀의 경우의 수를 구한다. 스타트팀을 구하면 남은 인원을 링크팀에 배치한다.

각 팀의 능력치를 구해 합의 차가 가장 작은 경우의 수를 구한다. 

 

문제 접근

스타트팀 n 에서 n/2 를 순서에 상관없이 뽑는 조합의 문제이다. 

ex) n = 6일 때 [1,2,3] 로 스타트팀을 구성한다면, [1,2,3] 이나 [2,1,3]이나 [3,1,2] 나 순서에 상관 없이 팀의 능력치는 각 팀원들로 만들 수 있는 모든 부분 집합 (x,y) 쌍의 합, 즉, (1,2)+(2,1)+(2,3)+{3,2)+(1,3)+(3,1) 이 될 것이기 때문이다. 

 

문제 풀이 

시도 끝에 아래 두 가지 풀이 참조 및 비교 

풀이1 : 재귀 이용

 

출처 - https://gobae.tistory.com/50

 

 

풀이2 : 구현 이용

 

출처 - https://github.com/jlee0505/algorithm-study/pull/1/commits/df6a36b419ef225e0d9196fc7126a3e762a0d194

 

배운 것 

1. min 값을 각각 0, MIN_SAFE_INTEGER, MAX_SAFE_INTEGER 의 차이:

MIN_SAFE_INTEGER, MAX_SAFE_INTEGER 는 각각 -9007199254740991, +9007199254740991 을 의미한다.

아래 코드의 min 의 초기 할당을 각각 0, MIN_SAFE_INTEGER, MAX_SAFE_INTEGER 으로 했을 때의 차이를 생각해보자.

 
min = Math.min(min, Math.abs(sSum - lSum));

 

2.  재귀로 풀 때와 구현으로 풀 때의 장단점:

첫 번째 제출은 풀이1(재귀)의 결과, 두 번째 제출은 풀이 2(구현)의 결과이다. 구현으로 풀면 가독성이 올라가고 직관적 이해가 쉽다는 장점이 있지만, 재귀로 푸는 것이 시간,공간 복잡도가 압도적으로 높다.


재귀는 여전히 어렵다.

 

'Board > 알고리즘' 카테고리의 다른 글

백준 2178 자바스크립트  (0) 2023.01.24
백준 2667 자바스크립트  (0) 2023.01.24
백준 14888 자바스크립트  (0) 2023.01.22
백준 2661 자바스크립트  (0) 2023.01.21
[알고리즘 공부] 20230115 2주차 회고  (0) 2023.01.16

나의 Notion - 알고리즘

2023년부터는 인턴과 기업 코딩테스트로 공부 방향을 잡았다. 어딜 가도 1차 관문이 되는 코딩테스트가 중요한 기회 때 발목 잡는 걸 원치 않았다. 

 

알고리즘 공부 시작, 지난 2주 돌아보기

1월 알고리즘 학습 계획표

 

 

2023 목표를 인턴과 기업 코딩테스트로 잡고, 어딜 가서든 1차 관문이 되는 코딩테스트의 ‘기본’을 1,2월안에 마무리 하기로 했다. 3,4월에는 본격적으로 기출을 풀며 여름방학/하반기 인턴 코테 지원(4~5월 지원)을 준비하고 싶었기 때문이다. 그리하여 2월까지 세운 러프한 계획은 이러했다:

  • 1월: 강의와 함께 빈출 알고리즘 핵심은 제대로 익혀두기(이코테 2021)
  • 2월: 백준 추천 50제 풀며 1월 배운 내용 복습 + 보강
  • 3월: 우테캠, 카카오, 토스 등 국내 기업 코딩테스트의 흐름을 주도하는 기업의 기출문제 풀어보기
  • 4월: 2차 관문인 과제 코테 준비 시작

 

 

 우선 이코테 2021 강의를 완강 + 80% 이해 및 체화를 목표로 1월 계획을 세웠다. 나는 정말 노베이스 상태에서 시작했기 때문에 전반적으로 어떻게 흘러가고 어떤 것들이 있는지 직접 한 번 훑고 싶었다. 지난 2주는 그런 시간이었다.

 

 그리디, 완전 탐색, 그리고 그래프 탐색(dfs, bfs)였다. dfs,bfs 는 중요하다는 말을 하도 많이 들어 감이 안잡혔지만 최대한 이해하고 넘어가려 했다. (관련 노션 보러가기)

 

 1월은 1회차기 때문에 문제를 많이 풀어보는 것보다 개념을 확실히 이해하는 게 더 중요하다고 생각했다. (이코테 기본 예제(2), 백준(1) - dfs, node 대신 edge 가 주어진 경우, 프로그래머스(5) - 스킵 )

 

 

Keep, Try, Problem

 회고를 쓰며 찾아보니 판교로 가는 길에서는 1주일 한 개념씩, 2~3문제를 풀어볼 것을 권한다. 예정보다 3일을 더 투자하여 (5,6,7일) 예제를 확실히 이해하고 추가로 백준 문제를 풀었다. 더 많은 문제를 풀었으면 좋았겠다는 아쉬움이 어쩔 수 없이 남는다. 하지만 카페 글을 참조해보니 오히려 이정도가 딱 맞았다는 생각이 든다. 외려 1주에 2개념을 잡았던 초기 계획이 불필요하게 빡세다는 느낌도 든다. 이에 따라

 

Keep 

- 무조건 문제 풀이보다 중요한 건 개념 이해

Problem

- 딱히 문제는 아니었지만... 한 개념 한 주씩 파는 것과 어떻게 다를지 다른 사람의 조언도 반영해볼 것.

- 예상했던 것보다 느슨해진다는 것 

Try 

- 한 개념 한 주씩: 두 개념 한 주씩 하던 지난 주와 후에 비교해볼 것

- 한 달 스프린트로 스터디를 개설하여 함께 뛰는 이가 있을 때 어떻게 달라질 수 있는지 비교해볼 것

- 불안요소를 글로써 가시화하고 제거할 수 있는 대책을 세우자.

 

다음 스텝은?

1. 한 개념 한 주씩 양치기 + 체화

다음 주부터는 본격적으로 양치기에 들어가려 한다. 지난 2주가 이코테 강의 위주의 전체 흐름 잡기 + 개념 익히기였다면, 다음 5주는 백준50제 위주의 양치기 체화 과정이 목표이다.

 

5주차 계획

 

다음 스텝: 2. 스터디와 함께 풀기

스터디를 개설했다.

 

이유:

  1. 해당 카페 포함 많은 이들이 같이 가는 스터디원이 있는 것을 강력 추천
  2. 지인과 네트워킹을 통해 혼자서는 몰랐을 시각/정보/인적자원 습득의 가능성
  3. 반복 문제 풀이인만큼 늘어지지 않게 함께 가는 메이트 만들기

걱정되는 부분:

지인과 함께 시작한 스터디라 아래 부분이 걱정되었다.

  1. 너무 루즈해지진 않을까?
  2. 친목 위주로 가서 집중력과 학습 효과가 떨어지면 어떡하지? 

어떻게 해결할 수 있을까?:

  1. 나의 불안요소: 쉽게 distracted 된다.
    1. 목표를 확실히 한다: 이 4주간 나는 무엇을 얻고자 하는가?
      1. 실버1,2 or 골드 4 를 달성 (모든 문제를 이해하고 풀이했다는 전제하)
  2. 상대에 대한 불안요소: 평소 함께 잘 놀던 지인이다.
    1. 주의사항을 상기한다:
      1. ‘성의 없는 공부’에 절대 관대하지 말 것.
    2. 전반적인 주차별 목표&계획과 구체적인 실행 컨텐츠 시간 장소 등을 확실히 하자.

다음 텀도 화이팅

 

'Board > 알고리즘' 카테고리의 다른 글

백준 2178 자바스크립트  (0) 2023.01.24
백준 2667 자바스크립트  (0) 2023.01.24
백준 14888 자바스크립트  (0) 2023.01.22
백준 2661 자바스크립트  (0) 2023.01.21
백준 14889 자바스크립트  (0) 2023.01.19

https://sites.google.com/site/unclebobconsultingllc/blogs-by-robert-martin/saying-no

 

Saying "NO" - Clean Coder

Uncle Bob Consulting LLC.

sites.google.com

---

Saying "NO"

Saying "NO".

Posted by Uncle Bob on 12/04/2009

I saw this cartoon in a tweet today. It’s the story of how a boss corrupts the work of a professional. It’s a funny cartoon, and a sad story that happens all too often in our profession. But who, exactly, was at fault?...
The difference between a laborer and a professional is that a laborer takes orders from his boss, and a professional provides input to his superiors. Laborers are hired to take direction. Professionals are hired to ensure that the direction chosen makes sense.

Imagine this conversation between a patient and a doctor:

Patient: “My arm hurts.” 
Doctor: “What would you like me to do about it?” 
Patient: “Make my arm stop hurting.” 
Doctor: “Do you want me to cut it off?, I can do that.” 
Patient: “No, I just want it to stop hurting.” 
Doctor: “I could cut all the nerves to your arm. That’ll stop it.” 
Patient: “Isn’t there something less drastic you could do?” 
Doctor: “Ooops, sorry, time for my break.”


Clearly we don’t expect doctors to behave this way. Even though the patient is the boss, the patient expects the doctor to have the answers and help set the direction.
Here’s another version of the conversation:

Patient: “I want you to cut my arm off.” 
Doctor: “What’s wrong with your arm?” 
Patient: “It hurts. I’m tired of it. Just cut it off.” 
Doctor: “Let me see your arm. Hmmm. Looks like you’ve got a sprain or perhaps a hairline fracture. We should take some X-Rays.” 
Patient: “No, just cut it off.” 
Doctor: “Sir, I do not cut off healthy arms.” 
Patient: “But I’m paying you. You have to do what I say!” 
Doctor: “No, sir, I don’t. Cutting off your arm would violate my oath.”


Which of these two doctors would you rather be? Now project these two doctors into your own profession, and which would you rather be?

Programmers are professionals. They know more about designing and implementing software systems than their bosses do. Indeed, they are hired for this knowledge and expertise. And they have a solemn duty to prevent their managers from doing things that would be harmful.

All this boils down to one simple thing. Professionals are willing to say “No”. When their managers come to them with direction that makes no sense, a professional programmer will refuse the direction.

Is this risky? Sure. But part of being a professional is the willingness to stand on principle. There are lines that a professional will not cross. Of course saying “No.” is only one side of the coin. Professionals are also expected to explain their positions, and come up with viable alternatives. Professionals negotiate with their superiors until both parties are satisfied with the chosen direction.

The poor web-designer schmuck in that cartoon was not behaving as a professional. He was behaving as a laborer. The fiasco at the end was his fault. He should have said “No.” and started a negotiation with his customer instead of just doing everything the customer said.

The cartoonist painted the web-designer as a wise but impotent victim, and the boss as the overbearing dufus. The reality is that the web-designer took the role of the victim voluntarily and shirked his responsibility to refuse direction that he considered harmful.

If you are a professional, you never allow yourself to be put in the role of the victim.

+ Recent posts