class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
int max = 1;
for(int i=1; i<nums.length; i++){
for(int j=0; j<i; j++){
if(nums[i]>nums[j]){
dp[i]=Math.max(dp[i], dp[j]+1);
}
}
max = Math.max(max, dp[i]);
}
return max;
}
}
dp[i] = i번째까지의 LIS 길이Arrays.fill(dp, 1) - 최소 길이 1현재 방식은 모든 이전 원소를 확인한다. Binary Search로 O(N log N) 가능하다.
// ✘ 매 iteration마다 갱신
for(int i=1; i<nums.length; i++){
// ...
max = Math.max(max, dp[i]);
}
// ✔ 마지막에 한 번만
return Arrays.stream(dp).max().getAsInt();
class Solution {
public int lengthOfLIS(int[] nums) {
List<Integer> tails = new ArrayList<>();
for(int num : nums){
int pos = Collections.binarySearch(tails, num);
if(pos < 0) pos = -(pos + 1);
if(pos == tails.size()){
tails.add(num);
} else {
tails.set(pos, num);
}
}
return tails.size();
}
}
핵심 아이디어:
tails[i] = 길이 i+1인 LIS의 마지막 원소 중 최솟값class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
for(int i=1; i<nums.length; i++){
for(int j=0; j<i; j++){
if(nums[i] > nums[j]){
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return Arrays.stream(dp).max().getAsInt();
}
}
| 방법 | 시간복잡도 | 공간복잡도 | Runtime |
|---|---|---|---|
| 원본 (DP) | O(N²) | O(N) | 38ms |
| Binary Search | O(N log N) | O(N) | ~5ms |
dp[i] = max(dp[j] + 1) for all j < i where nums[j] < nums[i]
nums = [10, 9, 2, 5, 3, 7, 101, 18]
tails 변화:
[10]
[9]
[2]
[2, 5]
[2, 3]
[2, 3, 7]
[2, 3, 7, 101]
[2, 3, 7, 18]
→ LIS 길이 = 4
tails는 실제 LIS가 아니라, 각 길이의 최적 후보다.
int pos = Collections.binarySearch(List<T> list, T key);
양수 (≥0): 찾은 인덱스
List<Integer> list = Arrays.asList(1, 3, 5, 7, 9);
int pos = Collections.binarySearch(list, 5); // pos = 2
음수 (<0): 못 찾음 → 삽입 위치 계산 필요
int pos = Collections.binarySearch(list, 6); // pos = -4
int insertPos = -(pos + 1); // insertPos = 3
insertPos = -(returnValue + 1)
List<Integer> tails = new ArrayList<>();
// tails = [2, 3, 7]
int pos = Collections.binarySearch(tails, 5);
// pos = -3 (5는 인덱스 2에 들어가야 함)
pos = -(pos + 1); // pos = 2
tails.set(2, 5); // [2, 3, 5]
for(int num : nums){
int pos = Collections.binarySearch(tails, num);
// 못 찾으면 삽입 위치 계산
if(pos < 0) pos = -(pos + 1);
// 끝에 추가 or 기존 값 교체
if(pos == tails.size()){
tails.add(num);
} else {
tails.set(pos, num);
}
}
#LeetCode #DP #BinarySearch #LIS #Java #최적화