BOJ[2529] - 부등호 by JavaScript
부등호
문제
언어
- JavaScript
문제 풀이 step 1
- 본 문제는 백 트래킹 문제로 조건에 만족하면 반복을 종료함으로써, 반복의 수를 줄여서 시간 복잡도를 낮추는 알고리즘입니다.
- 문제를 잘 분석해보면 반복의 수를 줄일 수 있는 방법을 많이 찾을 수 있습니다. 하나씩 알아보겠습니다.
- 우선 문제를 보면 0 ~ 9 이렇게 10 개의 수 중에서 부등호의 개수보다 1개 더 많이 선택한 후, 선택한 수들을 부등호 사이 사이에 넣어서 부등호 관계를 만족하는 수열을 찾아야 합니다.
- 문제를 보면 정답은 조건을 만족하는 수열들 중에서 최댓값과 최솟값을 찾는 것입니다.
- [반복을 줄이는 방법 1] 즉, 조건을 만족하는 모든 수열을 구할 필요가 없습니다. 그저 순서가 낮은 수열부터 올라가면서 최솟값을 찾으면 탐색을 종료하고, 순서가 높은 수열부터 내려오면서 최댓값을 찾으면 탐색을 종료하는 방식으로 정답을 구해도 됩니다.
- 저는 아래와 같은 방법으로 반복을 줄였습니다.
rec(arr, k, a, visited, res, number, 0);: 배열을 순서대로 입력rec(arr.reverse(), k, a, visited, res, number, 0);: 배열을 역순으로 입력if (res.length === 1) return;: 조건을 만족하는 수를 하나만 찾으면 종료
문제 풀이 step 2
- [반복을 줄이는 방법 2] 수열의 각 수를 고를 때마다 부등호 관계를 만족하는 지 판별하면 굳이 불필요한 탐색을 할 필요가 없습니다.
if (depth > 1 && !check(a, number)) return;: 선택한 수가 2개 이상이면 부등호 관계를 만족하는지 판별한다.- 이러한 코드가 백트래킹 기법이 요구하는 방식일 것입니다.
- 굳이 수열을 완성한 다음에 마지막에 부등호 관계를 만족하는지 판별하지 말고, 중간에 부등호 관계를 만족하지 않으면 탐색을 종료하는 방식으로 구현하면 탐색을 줄일 수 있습니다.
시행 착오 (삽질)
- 처음에는 최솟값과 최댓값을 구하는 함수 2 개를 구현했습니다.
- 정말 안좋았던 것은 두 함수의 코드가 똑같고 중간에 반복문의 식만 달랐습니다.
- getMin :
for (let i = 0; i < 10; i++) { - getMax :
for (let i = 9; i >= 0; i--) {
- getMin :
- 이 부분을 고쳐보고자 고심한 끝에
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];형태의 배열을 생성하고, 순서대로 그리고 역순으로 넣어주는 방식으로 해결할 수 있었습니다.- getMin :
rec(arr, k, a, visited, res, number, 0); - getMax :
rec(arr.reverse(), k, a, visited, res, number, 0);
- getMin :
- 항상 느끼지만 문제를 해결하는 데 있어 이런 방식의 접근은 간단해보이지만 중요한 것 같습니다.
소스 코드 1
const input = require("fs").readFileSync("/dev/stdin").toString().split("\n");
const check = (a, number) => {
let index = number.length - 1;
if (a[index - 1] === "<" && number[index - 1] > number[index]) return false;
if (a[index - 1] === ">" && number[index - 1] < number[index]) return false;
return true;
};
const rec = (arr, k, a, visited, res, number, depth) => {
// 조건을 만족하는 수열 하나만 찾아도 바로 탐색 종료
if (res.length === 1) return;
// 수를 선택할 때마다 부등호 관계를 만족하는지 판별
if (depth > 1 && !check(a, number)) return;
if (depth === k + 1) {
res.push(number.join(""));
return;
}
for (let i = 0; i < 10; i++) {
if (visited[i]) continue;
visited[i] = true;
number.push(arr[i]);
rec(arr, k, a, visited, res, number, depth + 1);
visited[i] = false;
number.pop();
}
};
const solution = (input) => {
const k = parseInt(input[0]);
const a = input[1].split(" ");
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const res = [];
const number = [];
const visited = Array(10).fill(false);
rec(arr, k, a, visited, res, number, 0);
const min = res.pop();
rec(arr.reverse(), k, a, visited, res, number, 0);
const max = res.pop();
return `${max}\n${min}`;
};
console.log(solution(input));