문제

https://app.codility.com/programmers/lessons/5-prefix_sums/min_avg_two_slice/

풀이

  1. 두 수의 평균은 두 수 중 작은 수보다 크거나 같다(같은 경우는 두 수가 같을 때)
  2. 이를 3개 이상의 N개의 수가 있다고 할 때 두 그룹으로 나눈다면 N개의 수의 평균은 두 그룹 중 합이 작은 것 보다 무조건 크기 때문에 N이 4개인 것이 답이 될 수 없다.
  3. 2개, 3개인 경우일 때 최소이므로 이 경우만 다 구해보면 답을 구할 수 있다.

코드

function solution(A) {
    let minAvg = (A[0] + A[1]) / 2;
    let minIdx = 0;
    for(let i=2;i<A.length;++i) {
        let avg = (A[i-2] + A[i-1] + A[i]) / 3;
        if(minAvg > avg) {
            minAvg = avg;
            minIdx = i-2;
        }
        avg = (A[i-1] + A[i]) / 2;
        if(minAvg > avg) {
            minAvg = avg;
            minIdx = i-1;
        }
    }
    return minIdx;
}

문제

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

풀이

정의대로 코드 작성한 후 메모이제이션 한다.

코드

let fs = require('fs');
// let input = fs.readFileSync('/dev/stdin').toString().split('\n');
let input = fs.readFileSync('./b9184.txt').toString().split('\n');

let readlineIdx = 0;

const readInput = () => input[readlineIdx++];

const fillMax = 0;
let table = new Array(21);

function w(a, b, c) {
  if (a <= 0 || b <= 0 || c <= 0) {
    return 1;
  }

  if (a > 20 || b > 20 || c > 20) {
    return w(20, 20, 20);
  }

  if (table[a][b][c] !== fillMax) {
    return table[a][b][c];
  }

  if (a < b && b < c) {
    let t1 = table[a][b][c - 1] = w(a, b, c - 1);
    let t2 = table[a][b - 1][c - 1] = w(a, b - 1, c - 1);
    let t3 = table[a][b - 1][c] = w(a, b - 1, c);
    return table[a][b][c] = t1 + t2 - t3;
  }


  let t1 = table[a - 1][b][c] = w(a - 1, b, c);
  let t2 = table[a - 1][b - 1][c] = w(a - 1, b - 1, c);
  let t3 = table[a - 1][b][c - 1] = w(a - 1, b, c - 1);
  let t4 = table[a - 1][b - 1][c - 1] = w(a - 1, b - 1, c - 1);
  return table[a][b][c] = t1 + t2 + t3 - t4;

}

function main() {
  for (let i = 0; i < 21; ++i) {
    table[i] = new Array(21);
    for (let j = 0; j < 21; ++j) {
      table[i][j] = new Array(21).fill(fillMax);
    }
  }
  while (true) {
    let [a, b, c] = readInput().split(' ');
    a = Number(a);
    b = Number(b);
    c = Number(c);
    if (a === -1 && b === -1 && c === -1) break;
    console.log(`w(${a}, ${b}, ${c}) = ${w(a, b, c)}`);

  }
}

main();

문제

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

풀이

1, 1 부터 시작해서 반시계방향으로 배열 만들어 간다.
만들다가 해당 숫자 나오면 좌표를 기록한다.
배열이 완성되면 배열과 좌표를 출력한다.

코드

let fs = require('fs');
// let input = fs.readFileSync('/dev/stdin').toString().split('\n');
let input = fs.readFileSync('./b1913.txt').toString().split('\n');

let readlineIdx = 0;

const readInput = () => input[readlineIdx++];

let dx = [0, 1, 0, -1];
let dy = [1, 0, -1, 0];
let answerLoca = { X: 0, Y: 2 };
function solution(table, t) {
  let cnt = t * t;
  let X = 0;
  let Y = 0;
  let nowDir = 0;
  let moveCnt = t;
  while (true) {
    if (nowDir === 1) {
      moveCnt--;
    }
    if (nowDir === 3) {
      moveCnt--;
    }

    for (let i = 0; i < moveCnt; ++i) {
      X = X + dx[nowDir];
      Y = Y + dy[nowDir];
      table[X][Y] = cnt--;
      if (table[X][Y] === findNum) {
        answerLoca = { X, Y };
      }
    }


    if (cnt === 0) {
      return;
    }
    nowDir = (nowDir + 1) % 4;
  }
}

let findNum;
function main() {
  let t = readInput();
  t = parseInt(t, 10);
  findNum = parseInt(readInput(), 10);
  let table = new Array(t + 1);
  for (let i = 0; i < t + 1; ++i) {
    table[i] = new Array(t).fill(0);
  }
  solution(table, t);
  for (let y = 1; y < t + 1; ++y) {
    let string = "";
    for (let x = 0; x < t; ++x) {
      if (x === t - 1) {
        string += table[x][y];
        break;
      }
      string += table[x][y] + ' ';
    }
    console.log(string);
  }
  console.log(answerLoca.Y, answerLoca.X + 1);

}

main();

문제

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

풀이

trie 자료구조에 입력값을 저장한다.
trie를 구성하던 중에 trie완성된 부분에서 node를 추가해나가는 건 다른 접두사가 있다는 것으로 "NO" 출력
trie를 구성하던 중에 끝났는데 지금까지 구성된 trie가 있다면 (this.pass로 표현) "NO" 출력

코드

let fs = require('fs');
// let input = fs.readFileSync('/dev/stdin').toString().split('\n');
let input = fs.readFileSync('./input.txt').toString().split('\n');

let readlineIdx = 0;

const readInput = () => input[readlineIdx++];

class Trie {
  constructor() {
    this.pass = false;
    this.end = false;
    this.child = {};
  }

  insert(trie, arr) {
    let el = parseInt(arr[0], 10);
    const nowChild = trie.child[el];
    if (nowChild === undefined) {
      const nT = new Trie();
      nT.pass = true;
      trie.child[el] = nT;
      if (arr.length === 1) {
        nT.end = true;
        return true;
      }
      return this.insert(nT, arr.slice(1));

    }
    if (nowChild.end === true) {
      return false;
    }
    if (arr.length === 1) {
      if (nowChild.pass) {
        return false;
      }
      nowChild.pass = true;
      nowChild.end = true;
      return true;
    }
    nowChild.pass = true;
    return this.insert(nowChild, arr.slice(1));
  }
}

function solution(temparr, n) {
  const trie = new Trie();
  for (let i = 0; i < n; ++i) {
    const nowArr = temparr[i].split("").filter((el) => el !== ' ');
    if (trie.insert(trie, nowArr) === false) {
      return false;
    }
  }
  return true;
}

function main() {
  let t = readInput();
  while (t--) {
    let n = readInput();
    let temparr = new Array();
    for (let i = 0; i < n; ++i) {
      temparr.push(readInput());
    }
    console.log(solution(temparr, n) === true ? 'YES' : 'NO');
  }
}

main();

문제

www.hackerrank.com/challenges/new-year-chaos/problem?h_l=interview&playlist_slugs%5B%5D%5B%5D=interview-preparation-kit&playlist_slugs%5B%5D%5B%5D=arrays&isFullScreen=true

풀이

  1. arr[i] = i+1 형태의 배열을 만든다.
  2. 이 배열을 입력배열 q와 똑같이 만들 수 있는지 판별하고 swap cnt를 기록한다.
  3. idx=0부터 증가하면서 조건을 만족하며 swap해 가면 반드시 본래위치에 idx+2 이하에 들어가야 하는 값이 있어야 한다.
  4. 조건 만족하면 cnt기록, 조건만족하지 않으면 종료시킨다.

코드

'use strict';

process.stdin.resume();
process.stdin.setEncoding('utf-8');

let inputString = '';
let currentLine = 0;

process.stdin.on('data', inputStdin => {
    inputString += inputStdin;
});

process.stdin.on('end', _ => {
    inputString = inputString.replace(/\s*$/, '')
        .split('\n')
        .map(str => str.replace(/\s*$/, ''));

    main();
});

function readLine() {
    return inputString[currentLine++];
}

// Complete the minimumBribes function below.
function minimumBribes(q) {
  let answer = 0;
  let arr = Array(100001);
  let arrCnt = Array(100001);
  for(let i=0;i<arr.length;++i) {
    arr[i] = i+1;
  }
  for(let i=0;i<q.length-1;++i) {
    let originValue = q[i];
    if(arr[i] !== originValue) {
      if(arr[i+1] !== originValue) {
        if(arr[i+2] !== originValue) {
          return 'Too chaotic';
        }
        let temp = arr[i+2];
        arr[i+2] = arr[i+1];
        arr[i+1] = temp;
        answer++;
      }
      let temp = arr[i+1];
      arr[i+1] = arr[i];
      arr[i] = temp;
      answer++;


    }
  }
  return answer;
}

function main() {
    const t = parseInt(readLine(), 10);

    for (let tItr = 0; tItr < t; tItr++) {
        const n = parseInt(readLine(), 10);

        const q = readLine().split(' ').map(qTemp => parseInt(qTemp, 10));

        console.log(minimumBribes(q));
    }
}

문제

https://programmers.co.kr/learn/courses/30/lessons/17677

풀이

  1. str1의 길이가 str2보다 짧으면 둘을 swap한다.
  2. 입력받은 문자열을 대문자로 바꾼다.
  3. 2글자씩 나누어 배열에 담는다.
  4. 2글자씩 나누었을 때 부적절한 단어가 있으면 drop 한다.
  5. 교집합과 합집합의 수를 구하기 위해 str1을 새로운 배열에 넣고 그곳에 str2의 원소를 하나씩 넣으며 교집합의 원소개수와 합집합 원소개수를 구한다.
  6. 값을 구한다.

문제

https://programmers.co.kr/learn/courses/30/lessons/12899?language=javascript#

풀이

  1. 3진수를 만든다.
  2. 3진수의 0이 있으면 윗자리 수에서 3을 빌려와서 3을 더해준다.

코드

function solution(n) {
  var answer = '';
  let tempans = Array();
  while(n > 0) {
    tempans.push(n % 3);
    n = Math.floor(n / 3);
  }
  for(let i=0;i<tempans.length-1;++i) {
    if(tempans[i] <= 0) {
    tempans[i] += 3;
    tempans[i+1]--;
    } 
  }

  tempans.reverse()
    .forEach((el) => {
      if(el === 0) {
        return;
      }
      if(el === 3) {
        answer += '4';
        return;
      } 
      answer += el;
    })
  return answer;
}

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

[HackerRank] New Year Chaos  (0) 2021.01.08
[프로그래머스] 뉴스클러스터링  (0) 2021.01.07
백준 20055 C++ 컨베이어 벨트 위의 로봇  (0) 2020.12.31
Codility - MinAbsSumOfTwo  (0) 2020.12.30
백준 4902 삼각형의 값 c++  (0) 2020.09.17

문제

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

풀이

조건대로 차례대로 구현하면 됐다.

  1. 컨베이어 벨트를 회전시킨다.
    1-1 N위치에 로봇이 있다면 로봇을 내린다.
  2. 로봇을 이동시킨다.
    2-1 N위치에 로봇이 있다면 로봇을 내린다.
    2-2 로봇이 이동할 때 내구도를 1 감소시킨다.
  3. 1위치에 로봇을 올린다.
    3-1 1위치에 로봇을 올릴 때 내구도를 1 감소시킨다.
  4. 종료조건을 확인한다.

코드

#include <iostream>

using namespace std;

struct can {
  bool onRobot;
  int left;
};

int N, K;
can A[1001];

void rotateA() {
  can temp = A[N * 2 - 1];
  for(int i=N * 2-1;i>=0;--i) {
    A[i] = A[i-1];
  } 
  A[0] = temp;
  if(A[N-1].onRobot) {
    A[N-1].onRobot = false;
  }
}

void move() {
  for(int i=N - 2;i>=0;--i) {
    if(A[i].onRobot) {
      int nextIdx = i + 1;
      if(!A[nextIdx].onRobot && A[nextIdx].left != 0) {
        if(nextIdx == N-1) {
          A[i].onRobot = false;
          A[nextIdx].left--;
          continue;
        }
        A[i].onRobot = false;
        A[nextIdx].onRobot = true;
        A[nextIdx].left--;
      }
    }
  }
}

void pushRobot() {
  if(!A[0].onRobot && A[0].left != 0) {
    A[0].onRobot = true;
    A[0].left--;
  }
}

int cntEmptyCan() {
  int ret = 0;
  for(int i=0;i<N * 2;++i) {
    if(A[i].left == 0) {
      ret++;
    } 
  }
  return ret;
}

void printLeft() {
  cout << "PL" << endl;
  for(int i=0;i<N * 2;++i) {
    cout << A[i].left << ' ';
  }
  cout << endl;
  for(int i=0;i<N * 2;++i) {
    cout << A[i].onRobot<< ' ';
  }
  cout << endl;
}

int main(void) {
  cin >> N >> K;
  for(int i=0;i<N * 2;++i) {
    cin >> A[i].left;
    A[i].onRobot = false;
  }

  int ans = 1;
  while(true) {
    rotateA();
    move();
    pushRobot();
    if(cntEmptyCan() >= K) {
      cout << ans;
      return 0;
    } 
    ans++;
  }
  return 0;
}

문제

https://app.codility.com/programmers/lessons/15-caterpillar_method/min_abs_sum_of_two/

풀이

  1. 입력 배열을 정렬한다.
  2. 배열의 양 끝 값의 합부터 시작해서 점점 배열의 안쪽으로 들어가며 계산한다.
    • 양 끝 값의 합을 구하고 둘 중 절댓값이 큰 값의 Index를 한칸 안쪽으로(시작 index는 +1, 끝 index는 -1) 보낸다.
  3. 두 index가 같아졌을 때 계산을 종료하고 이 때의 index가 가리키는 값이 절대값이 가장 작은 원소이므로 이 값의 2배의 절대값도 정답의 후보다.

문제 이해

삼각형 안에 숫자가 있고 만들 수 있는 부분 삼각형의 숫자 총합 중 최대값을 구하는 문제다. 숫자 범위가 정수이기 때문에 한 값이 튀게 되면 결과를 예상할 수 없어 모든 경우를 다 구해봐야한다.

평범한 dp로는 문제를 풀 수 없다. 메모이제이션 해야하는 양이

row : 400, col : 400 * 2 + 1, 부분삼각형 경우의수 : 400 으로 메모리 제한을 초과한다.

int memo[400][801][400] // 메모리 제한 초과 

모든 경우의 수를 다 구한다면 시간 복잡도는

r * c * 경우의수 * 경우의 수 뽑아 더하는 것 = 400 * 800 * 400 * 약 400 = 51,200,000,000

으로 시간제한 1초를 초과한다.

경우의 수를 뽑아 더하는 것은 처음 입력받을 때 누적 합을 구해 둔 다음 O(1)만에 한 row의 합을 구할 수 있도록 하면 시간제한안에 들어온다.

풀이

Process

void process() {
  for(int r=N-1;r>=0;--r) {
    for(int c=0;c<2*r+1;c+=2) {
      cal(r,c);
      if(c != 2 * r) {
        reverseCal(r,c+1);
      }
    }
  } 
 }

모든 점을 돌면서 한번씩 해봐야한다.

column은 짝수 번째일 때 size 2이상의 피라미드형 부분 삼각형을 만들 수 있다.

홀수 번째일때는 size 2 이상의 역삼각형을 만들 수 있다.

input 과 부분합

void input() {
  ans = -1001;
  memset(cSum, 0, sizeof(cSum));
  memset(table, 0, sizeof(table));
  for(int r=0;r<N;++r) {
    for(int c=0;c<2*r+1;++c) {
      cin >> table[r][c];
      ans = max(table[r][c], ans);
      if(c != 0) 
        cSum[r][c] += cSum[r][c-1] + table[r][c];
      else
        cSum[r][c] = table[r][c];
    }
  }
}

값 받으면서 부분합을 같이 계산해주었다.

피라미드형 부분 삼각형 계산

void cal(int r, int c) {
  int pSum = 0;
  for(int s=1;s<=N-r+1;++s) {
    if(c == 0) 
      pSum += cSum[r + s - 1][c + 2 * (s - 1)];
    else 
      pSum += cSum[r + s - 1][c + 2 * (s - 1)] - cSum[r + s - 1][c - 1];
    ans = max(pSum, ans);
  }
}

size는 지금 구해야 하는 row에서 더해야 하는 길이이다. size1 일 때는 r, c(시작점) 에서 부분 삼각형의 size 가 1일 때 값을 구하고 ans에 max값으로 최신화한다. 다음 size를 증가시키면서 한 row씩 증가시키며 해당하는 부분의 합을 더한다.

한 row에 해당하는 영역을 구하는 점화식이 위와 같이 나와 그대로 사용하면 된다.

역 피라미드형 부분 삼각형 계산

void reverseCal(int r, int c) {
 int pSum = 0;
  for(int s=1;s<=N;++s) {
    if(c >= 2 * s - 1 && 2 * r - c >= s * 2 - 1) {
      if(c - 2 * s + 1 >= 0) {
        pSum += cSum[r - s + 1][c] - cSum[r - s + 1][c - 2 * s + 1];
      } else {
        pSum += cSum[r - s + 1][c];
      }
    } else {
      break;
    }
    ans = max(pSum, ans);
  }
}

역 피라미드형은 row를 감소시키며 구해나간다. 점화식은 위와 같다.

종료조건을 따로 추가했다.

역 피라미드형이 가능한 size를 정하는데 위와 같은 방식으로 생각했다. 지금 size로 역 피라미드가 만들어지려면 선택한 c의 왼쪽, 오른쪽에 역피라미드의 가장 넓은 부분의 개수만큼 있어야 한다.

테스트 케이스

4 1 1 -1 1 1 -1 1 -1 1 1 -1 1 -1 1 -1 1
5 0 0 0 0 0 99 99 99 0 0 0 0 99 0 0 0 0 0 0 0 0 0 0 0 0
3 6 -24 0 12 -10 12 40 -4 6
5
         0
       0 0 0
     299 0 0 0 9
   -9 0 0 0 9 -9999 9
 -9 28 -9 0 9 9 9 9 9
5
         0
       0 0 0
     9 9 9 9 9
   0 -9 9 9 9 -9 0
 0 0 0 -9 9 -9 0 0 0
6
          0
        0 0 0
      0 1000 1000 1000 0
    0 9 9 -2 9 9 0
  0 0 0 9 9 9 0 0 0
0 0 0 0 0 9 -9999 0 0 0 0
6
          0
        0 0 0
      0 0 0 0 0
    0 9 9 9 9 9 0
  0 0 0 9 9 9 0 0 0
0 0 0 0 0 9 -9999 0 0 0 0
6
          0
        0 0 0
      0 1000 1000 1000 0
    0 9 9 -2 9 9 0
  0 0 0 9 9 9 0 0 0
0 0 0 0 0 9 -9999 0 0 0 0
0

// answer
1. 4
2. 396
3. 54
4. 336
5. 54
6. 3061
7. 81
8. 3061

코드

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

int N;
int table[401][801];
int cSum[401][801];
int ans;
void input() {
  ans = -1001;
  memset(cSum, 0, sizeof(cSum));
  memset(table, 0, sizeof(table));
  for(int r=0;r<N;++r) {
    for(int c=0;c<2*r+1;++c) {
      cin >> table[r][c];
      ans = max(table[r][c], ans);
      if(c != 0) 
        cSum[r][c] += cSum[r][c-1] + table[r][c];
      else
        cSum[r][c] = table[r][c];
    }
  }
}

void cal(int r, int c) {
  int pSum = 0;
  for(int s=1;s<=N-r+1;++s) {
    if(c == 0) 
      pSum += cSum[r + s - 1][c + 2 * (s - 1)];
    else 
      pSum += cSum[r + s - 1][c + 2 * (s - 1)] - cSum[r + s - 1][c - 1];
    ans = max(pSum, ans);
  }
}

void reverseCal(int r, int c) {
 int pSum = 0;
  for(int s=1;s<=N;++s) {
    if(c >= 2 * s - 1 && 2 * r - c >= s * 2 - 1) {
      if(c - 2 * s + 1 >= 0) {
        pSum += cSum[r - s + 1][c] - cSum[r - s + 1][c - 2 * s + 1];
      } else {
        pSum += cSum[r - s + 1][c];
      }
    } else {
      break;
    }
    ans = max(pSum, ans);
  }
}

void process() {
  for(int r=N-1;r>=0;--r) {
    for(int c=0;c<2*r+1;c+=2) {
      cal(r,c);
      if(c != 2 * r) {
        reverseCal(r,c+1);
      }
    }
  } 
 }

void output() {
  static int cnt = 1;
  cout << cnt++ << ". " << ans << endl;
}

int main(void) {
  freopen("b4902.txt", "r", stdin);
  cin >> N;
  while(N != 0) {
    input();
    process();
    output();
    cin >> N;
  }
}

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

백준 20055 C++ 컨베이어 벨트 위의 로봇  (0) 2020.12.31
Codility - MinAbsSumOfTwo  (0) 2020.12.30
백준 2916 자와 각도기 c++  (0) 2020.09.15
백준 2210 숫자판 점프 c++  (0) 2020.09.15
백준 2933 미네랄 C++ 풀이  (0) 2020.09.12

+ Recent posts