문제
수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.
예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.
입력
첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.
둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)
출력
첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.
둘째 줄에는 가장 긴 증가하는 부분 수열을 출력한다. 그러한 수열이 여러가지인 경우 아무거나 출력한다.
예제
예제 입력 1
예제 출력 1
내 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const [N, input] = require("fs") .readFileSync("/dev/stdin") .toString() .trim() .split("\n"); const A = input.split(" ").map(Number);
const DP = Array.from({ length: N }, () => 1);
for (let i = 1; i < N; i++) { for (let j = 0; j < i; j++) { if (A[j] < A[i]) { DP[i] = Math.max(DP[i], DP[j] + 1); } } }
const LIS = Math.max(...DP);
let LIS_Array = []; for (let i = 0; i < N; i++) { const index = DP.findIndex((elem) => elem === i + 1); LIS_Array.push(A[index]); }
console.log(LIS); console.log(LIS_Array.join(" "));
|
- 기존 LIS를 구하는 로직에서 DP에 해당하는 LIS뿐만 아니라 그 때의 배열까지 생성해주도록 하였다.
- 처음 배열 길이만큼 반복문을 순회하면서 DP값에서 Index를 찾는다. 해당 index의 A 수열의 값을 넣어준다.
- 왜 틀렸는지 이유를 모르겠어서 해설을 보게되었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| const [N, input] = require("fs") .readFileSync("/dev/stdin") .toString() .trim() .split("\n"); const A = input.split(" ").map(Number);
const DP = Array.from({ length: N }, () => 1);
for (let i = 1; i < N; i++) { for (let j = 0; j < i; j++) { if (A[j] < A[i]) { DP[i] = Math.max(DP[i], DP[j] + 1); } } }
let LIS = Math.max(...DP); let LIS_Array = [];
for (let i = N - 1; i >= 0; i--) { if (DP[i] === LIS) { LIS_Array = [A[i], ...LIS_Array]; LIS--; } }
console.log(LIS_Array.length); console.log(LIS_Array.join(" "));
|
- 이전 내 코드는 findIndex 메서드로 제일 앞에서 부터 해당 인덱스를 찾아주도록 하였다. 하지만 이런 경우 반례가 생긴다. 왜냐하면 내가 처음에 DP의 초기값을 모두 1로 설정해두었기 때문에 LIS_Array의 배열의 데이터가 이상하게 들어올 수 있다
반례
N = 14, A = [10, 12, 1, 3, 5, 6, 7, 10, 12, 2, 4, 7, 10, 12]
- findIndex로 앞에서부터 찾았을 경우: LIS_Array = [10, 12, 5, 6, 7, 10, 12]
- 반복문 역순으로 찾았을 경우: LIS_Array = [1, 3, 5, 6, 7, 10, 12]