728x90
문제
https://www.acmicpc.net/problem/11054
수열 S가 어떤 수 Sk를 기준으로 S1 < S2 < ... Sk-1 < Sk > Sk+1 > ... SN-1 > SN을 만족한다면, 그 수열을 바이토닉 수열이라고 한다.
예를 들어, {10, 20, 30, 25, 20}과 {10, 20, 30, 40}, {50, 40, 25, 10} 은 바이토닉 수열이지만, {1, 2, 3, 2, 1, 2, 3, 2, 1}과 {10, 20, 30, 40, 20, 30} 은 바이토닉 수열이 아니다.
수열 A가 주어졌을 때, 그 수열의 부분 수열 중 바이토닉 수열이면서 가장 긴 수열의 길이를 구하는 프로그램을 작성하시오.
[ 입력 ]
첫째 줄에 수열 A의 크기 N이 주어지고, 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ Ai ≤ 1,000)
[ 출력 ]
첫째 줄에 수열 A의 부분 수열 중에서 가장 긴 바이토닉 수열의 길이를 출력한다.
풀이
- 수열에서 한 수를 기준으로 왼쪽의 오름차순, 오른쪽의 내림차순 최대길이를 구해보면 된다.
- 가운데에 끼일 수를 num번이라 하고, num-1번부터 감소하면서 더 작은 수를 체크한다.
- 더 작은 수를 발견하면, 그 수를 수열에 포함한 게 최대길이일지, 포함하지 않은 게 최대길이일지 체크한다.
- 반대로 num+1번부터 증가하면서도 같은 방식으로 체크한다.
// 백준 - 가장 긴 바이토닉 부분 수열(11054)
let leftDp = [];
let rightDp = [];
let list = [];
const solution = ( N ) => {
leftDp = new Array(N).fill(-1);
rightDp = new Array(N).fill(-1);
for(let i = 0; i < N; i++) {
leftUp(i); // 왼쪽 수열 체크
rightDown(i); // 오른쪽 수열 체크
}
let max = 0;
for(let i = 0; i < N; i++) {
// 1을 더하는 이유: 왼쪽, 오른쪽을 나누는 기준인 가운데 수도 포함해야 함
max = Math.max(max, leftDp[i] + rightDp[i] + 1);
}
console.log(max);
};
// 왼쪽 오름차순
const leftUp = (num) => {
// 탐색하지 않은 위치
if(leftDp[num] == -1) {
leftDp[num] = 0;
for(let i = num - 1; i >= 0; i--) {
// 왼쪽에서 본인보다 작은 수 발견
if(list[num] > list[i]) {
// 해당 수를 포함하는 게 더 수열이 길지 확인
leftDp[num] = Math.max(leftDp[num], leftUp(i) + 1);
}
}
}
return leftDp[num];
}
// 오른쪽 내림차순
// 왼쪽 오름차순
const rightDown = (num) => {
// 탐색하지 않은 위치
if(rightDp[num] == -1) {
rightDp[num] = 0;
for(let i = num + 1; i < rightDp.length; i++) {
// 오른쪽에서 본인보다 작은 수 발견
if(list[num] > list[i]) {
// 해당 수를 포함하는 게 더 수열이 길지 확인
rightDp[num] = Math.max(rightDp[num], rightDown(i) + 1);
}
}
}
return rightDp[num];
}
// 테스트용
/*
const fs = require('fs');
const input = fs.readFileSync(__dirname + '/input.txt').toString().split('\n');
const N = parseInt(input[0]);
list = input[1].split(' ').map(el => parseInt(el));
solution(N);
*/
// 제출용
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout,
});
let input = [];
readline.on("line", (line) => {
input.push(line);
}).on("close", () => {
const N = parseInt(input[0]);
list = input[1].split(' ').map(el => parseInt(el));
solution(N);
process.exit();
});
728x90
'Programming > JavaScript' 카테고리의 다른 글
[백준/JavaScript] 평범한 배낭(12865) (0) | 2024.06.13 |
---|---|
[백준/JavaScript] 주사위 굴리기(14499) (1) | 2024.06.10 |
[백준/JavaScript] 수 묶기(1744) (0) | 2024.06.04 |
[프로그래머스/JavaScript] 뒤에 있는 큰 수 찾기(Lv.2) (0) | 2024.05.26 |
[프로그래머스/JavaScript] 롤케이크 자르기(Lv.2) (0) | 2024.05.25 |