[백준 12015번 C/C++] 가장 긴 증가하는 부분 수열 2
[백준 12015번 C/C++] 가장 긴 증가하는 부분 수열 2

https://www.acmicpc.net/problem/12015
12015번: 가장 긴 증가하는 부분 수열 2
첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)
www.acmicpc.net
해결 전략
최대 증가길이 수열, 이분 탐색
Longest Increasing Subsequence, LIS
처음 시도한 코드 - 시간 초과
#include <iostream> #include <vector> using namespace std; int n, result; vector<int> v, LIS; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n; v.resize(n); // 주어진 값을 넣는 배열 LIS.resize(n); // 각 숫자의 최대부분 증가 길이를 기록하는 배열 for (int i = 0; i < n; i++) { cin >> v[i]; } LIS[0] = 1; //첫 숫자의 LIS는 무조건 1이다. for (int i = 1; i < n; i++) { int maxValue = 0; // (i~1) ~ 0까지 탐색 for (int j = i - 1; j >= 0; j--) { // v[i]의 숫자보다 작은 숫자들 중 최대부분증가 길이가 maxValue보다 큰 경우 // maxValue값이 0으로 시작해서 계속해서 큰 값으로 갱신된다. // 결국에 해당 if조건에서 가장 큰 LIS[j]값이 가장 큰 maxValue값이 된다. if (v[j] < v[i] && LIS[j] > maxValue) maxValue = LIS[j];//maxValue은 (i-1) ~ 0번까지 LIS 중 가장 큰 값이 된다. } //LIS[i]보다 작은 숫자에서 가질 수 있는 최대부분증가 길이(위에서 설정한 maxValue)에서 +1 해준다. LIS[i] = maxValue + 1; //i번째 최대부분증가 길이가 가장 큰 값인지 검사하고 가장 큰 값이면 result값을 LIS[i]로 갱신한다. if (result < LIS[i]) result = LIS[i]; } cout << result; return 0; }
이중 배열을 사용해서 시간 초과가 나온다.
코드 - 이분탐색을 사용한 코드
#include <iostream> #include <vector> using namespace std; int n; // 입력받을 정수의 개수 vector<int> v, LIS; // v는 입력받은 정수들을 저장하는 벡터, LIS는 최장 증가 부분열을 저장하는 벡터 // key값 이상의 크기의 수 중에서 가장 먼저 나온 수의 인덱스를 반환하는 함수 int BinarySearch(vector<int>& v, int key) { int left = 0; int right = v.size() - 1; int mid; // 이진 탐색 시작 while (left < right) { int mid = (left + right) / 2; if (key > v[mid]) { // 찾고자 하는 값이 중간 값보다 크면 왼쪽 범위를 줄임 left = mid + 1; } else { // 찾고자 하는 값이 중간 값보다 작거나 같으면 오른쪽 범위를 줄임 right = mid; } } return right; // 탐색 완료 후 인덱스 반환 } void Solve() { LIS.push_back(v[0]); // LIS에 첫 번째 값을 추가 for (int i = 1; i < n; i++) { if (LIS.back() < v[i]) { // 현재 검사하고 있는 값이 LIS 마지막 원소보다 크면 LIS에 추가함. LIS.push_back(v[i]); } else { int idx = BinarySearch(LIS, v[i]); // 그렇지 않으면 해당 원소가 들어갈 위치를 찾아서 그 위치에 원소를 업데이트 함. LIS[idx] = v[i]; } } cout << cnt; // 최장 증가 부분열의 길이 출력. 즉, 현재까지 만들어진 최대 길이 출력. } int main() { cin.tie(0); cout.tie(0); cin >> n; v.resize(n); for (int i = 0; i < n; i++) { cin >> v[i]; } Solve(); return 0; }
짧은 코드
#include <iostream> #include <vector> #include <algorithm> using namespace std; int n; // 입력받을 정수의 개수 vector<int> v; // 최장 증가 부분열(LIS)를 저장하는 벡터 int main() { cin >> n; // 정수의 개수를 입력받음 for (int i = 0; i < n; i++) { int input; cin >> input; if (v.empty() || v.back() < input) // 벡터가 비어있거나, 마지막 원소보다 현재 원소가 클 경우에는 벡터에 원소를 추가합니다. v.push_back(input); else // 그렇지 않은 경우, lower_bound 함수로 현재 원소보다 크거나 같은 첫 번째 위치(원소)를 찾아서, // 그 위치의 값을 현재 원소로 업데이트합니다. *lower_bound(v.begin(), v.end(), input) = input; } cout << v.size(); // 최종적으로 LIS의 길이 출력 }
'⭐ 코딩테스트 > 백준' 카테고리의 다른 글
[백준 7562번 C/C++] 나이트의 이동 (0) | 2023.09.01 |
---|---|
[백준 1697번 C/C++] 숨바꼭질 (0) | 2023.08.31 |
[백준 2580번 C/C++] 스도쿠 (0) | 2023.08.20 |
[백준 1012번 C/C++] 유기농 배추 (0) | 2023.08.18 |
[백준 11660번 C/C++] 구간 합 구하기 5 (0) | 2023.08.16 |
댓글
이 글 공유하기
다른 글
-
[백준 7562번 C/C++] 나이트의 이동
[백준 7562번 C/C++] 나이트의 이동
2023.09.01 -
[백준 1697번 C/C++] 숨바꼭질
[백준 1697번 C/C++] 숨바꼭질
2023.08.31 -
[백준 2580번 C/C++] 스도쿠
[백준 2580번 C/C++] 스도쿠
2023.08.20 -
[백준 1012번 C/C++] 유기농 배추
[백준 1012번 C/C++] 유기농 배추
2023.08.18
댓글을 사용할 수 없습니다.