import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* packageName : org.example.병사배치하기
* fileName : Main
* author : ipeac
* date : 2023-08-31
* description :
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2023-08-31 ipeac 최초 생성
*/
public class Main {
public static void main(String[] args) {
try (
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
) {
int n = Integer.parseInt(br.readLine());
if (!(1 <= n && n <= 2000)) {
String errorMessage = String.format("n 의 범위는 1 <= n <= 2000 입니다. n = %d", n);
throw new IllegalArgumentException(errorMessage);
}
String[] input = br.readLine()
.split(" ");
List<Soldier> soldiers = new ArrayList<>();
for (int i = 0; i < n; i++) {
soldiers.add(Soldier.from(i, input[i]));
}
int[] dp = new int[n];
// 자체 dp 에서 최대 카운트를 각자 1씩은 가질 수 있음
Arrays.fill(dp, 1);
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
Soldier targetSoldier = soldiers.get(i);
Soldier comparableSoldier = soldiers.get(j);
if (comparableSoldier.isStrongerThan(targetSoldier)) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int maxLength = Arrays.stream(dp)
.max()
.getAsInt();
int answer = n - maxLength;
System.out.println(answer);
} catch (IOException e) {
e.printStackTrace();
}
}
public static class Soldier {
private final int index;
private final int power;
public Soldier(int index, int power) {
if (!(0 <= index && index <= 2000)) {
String errorMessage = String.format("index 의 범위는 0 <= index <= 2000 입니다. index = %d", index);
throw new IllegalArgumentException(errorMessage);
}
if (!(1 <= power && power <= 1000000000)) {
String errorMessage = String.format("power 의 범위는 1 <= power <= 1000000000 입니다. power = %d", power);
throw new IllegalArgumentException(errorMessage);
}
this.index = index;
this.power = power;
}
public int getIndex() {
return index;
}
public int getPower() {
return power;
}
public boolean isStrongerThan(Soldier other) {
Objects.requireNonNull(other, "other 는 null 이 될 수 없습니다.");
return this.power > other.power;
}
public static Soldier from(int index, String power) {
Objects.requireNonNull(power, "power 는 null 이 될 수 없습니다.");
int powerValue = Integer.parseInt(power);
return new Soldier(index, powerValue);
}
}
}
- DP → LIS 문제 였다고 한다.
- LIS란?
- Longest Increasing Subsequence
- 주어진 수열에서 가장 긴 증가하는 수열을 찾는 문제
- 두 가지 방식이 있다고 한다.
- O(n^2) 의 로직과
- O(n log n) 의 로직
- n log n 로직은 솔직히 이해하기가 좀 난해하여 O(n^2) 로직을 적용하였다.
- LIS란?
int[] dp = new int[n];
// 자체 dp 에서 최대 카운트를 각자 1씩은 가질 수 있음
Arrays.fill(dp, 1);
- 일단 본인값을 포함한다면 항상 최소 1의 길이는 모든 수열을 기준으로 해도 가지게 된다.
- dp 배열을 전부 1로 설정함.
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
Soldier targetSoldier = soldiers.get(i);
Soldier comparableSoldier = soldiers.get(j);
if (comparableSoldier.isStrongerThan(targetSoldier)) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
- 기준되는 솔저를 하나 잡고
- 비교되는 솔저도 하나 잡는다.
- 기준되는 솔저 왼쪽의 솔저들을 순회해야하기에
- 결국 이중 반복문인 O(n^2) 이 될 수 밖에 없다.
- 기준이 되는 솔저의
power
가 항상 비교되는 솔저의power
보다 작아야한다.- 그리고 비교되는 솔저의 값보다
작다면
해당 비교되는 솔저가 가진 최장길이 값에 + 1 이 되어야하고, 별도로기준의 되는 솔저
의 최장길이 값이 더 크다면 그 값을 그대로 두어야하기에
dp[i]
도 별도로 필요하다.Math.max(dp[i], dp[j] + 1);
- 그리고 비교되는 솔저의 값보다
int maxLength = Arrays.stream(dp)
.max()
.getAsInt();
- dp 배열에서 최댓값을 결국 순회하면서 최댓값을 찾아와서
- 솔저의 수에 해당
maxLength
를 빼주면 된다.
- 별도로 dp에 값을 담기만하고, maxCount 를 별도로 이중 for문 > if 문 안에서 구해줘도 될 것 같다.
- 굳이 stream을 돌아서 O(n) 을 수행할 필요는 없는 것 같다.
int maxCount = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
Soldier targetSoldier = soldiers.get(i);
Soldier comparableSoldier = soldiers.get(j);
if (comparableSoldier.isStrongerThan(targetSoldier)) {
dp[i] = Math.max(dp[i], dp[j] + 1);
maxCount = Math.max(maxCount, dp[i]);
}
}
}
하지만 입력 데이터 자체가 모수가 적어서
별 차이는 없었다.
Uploaded by N2T
'자바 > 알고리즘' 카테고리의 다른 글
[알고리즘] 회전하는큐 (0) | 2023.09.12 |
---|---|
[알고리즘] four squares (0) | 2023.09.10 |
[알고리즘]한줄로 서기 (0) | 2023.08.31 |
[알고리즘]퇴사 (0) | 2023.08.29 |
[알고리즘] 바이러스 (0) | 2023.08.28 |