1. ๋ฌธ์ ์ค๋ช ๐
ํ ๊ฐ ์ด์์ ์ผ์ด ์กด์ฌํ๊ณ , ์ผ๋ง๋ค ์์์๊ฐ
, ๋์๊ฐ
, ์๋ฃํ์ ๋ ์ด์ต
์ด ์ฃผ์ด์ง ๋, ์ฃผ์ด์ง ์ผ๋ จ์ ์ผ๋ค์์ ๋์ฌ ์ ์๋ ์ต๋ ์ด์ต
์ ๋ฐํํ๋ผ.
์กฐ๊ฑด
- ์ ํํ ์ผ๋ค์ ์๋ก ์ผ์ ์งํ ์๊ฐ์ด ๊ฒน์น๋ฉด ์๋๋ค.
- A๋ผ๋ ์ผ์ endTime = X ์ด๊ณ , B๋ผ๋ ์ผ์ startTime = X์ด๋ฉด A์ B๋ฅผ ์ฐ๋ฌ์ ์ผํ ์ ์๋ค. ์ด๋ ๊ฒน์น๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ์ง ์๋๋ค.
2. ์ ๊ทผ ๋ฐฉ์ ๐๏ธ
KEY WORD
: DP
(1) ์ด๊ธฐํ
(๊ฐ) ๊ฐ๊ฐ ์ฐ์ฌ๋์ด ์๋ startTime, endTime, profit์ ๊ฐ์ ์ผ ๋จ์๋ก ๋ฌถ์ด์ ๋์ด โ class Job
+ ArrayList
(๋) ArrayList๋ฅผ ์์ ์๊ฐ์ด ์ด๋ฅธ ์์ผ๋ก ์ ๋ ฌ
(๋ค) DP
์ฉ ๋ฐฐ์ด maxProfit[] ๋ง๋ค๊ธฐ (maxProfit[i] = ArrayList์ i๋ฒ์งธ ์ผ์ ์ ํํ ์ ์๋ ์์ ์์ ๋์ ์ต๋ ์ด์ต)
(๋ผ) TreeMap<Integer, Integer> ์์ฑ: Key
: startTime, Value
: ํด๋น ์์์๊ฐ์ ์์ํ์ ๋ ๋์ ์ต๋ ์ด์ต์ index
maxProfit
์ ๋ฐฐ์ด ํฌ๊ธฐ๊ฐ ArrayList๋ณด๋ค 1 ํฐ ๊ฒ์ ๋ณผ ์ ์๋๋ฐ, ์ด๋ MaxProfit์ ๊ณ์ฐ์ด ์ด์ ์์๋ฅผ ํ์ฉํจ์ผ๋ก, OutOfArrayError
๊ฐ ๋ฐ์ํ์ง ์๋๋ก ํ๊ธฐ ์ํด ํ ์นธ ๋ ๋ง๋ ๊ฒ์ด๋ค.
(2) ๊ณ์ฐ
์๊ฐ ์ ์ ์ผ ๋์ค์ธ ์๋ฒ๋ถํฐ ์ญ์์ผ๋ก ๊ณ์ฐํ๋ TOP-DOWN
ํ์์ DP๋ฅผ ์ฌ์ฉํ ์์ .
์ ํ์
: maxProfit[i] = Math.max(maxProfit[i+1], cur_profit[i] + maxProfit[nonOverLappingFirstIndex])
ํด์:
i๋ฒ์งธ Job์ ๊ณ ๋ฅผ ์ ์๋ ์์ ์ ์ต๋์ด์ต์ ๋ ์ค ํ๋์ด๋ค.
- a. i ๋ฒ์งธ ์ผ์ ๊ณ ๋ฅด์ง ์๊ณ , ์ด์ ๊น์ง ํ ์ผ๋ก ์ด๋ฃฌ ์ต๋๊ฐ์ ๋ต์ตํ๊ฑฐ๋
- b. i๋ฒ์งธ ์ผ์ ๊ณ ๋ฅด๊ณ , i๋ฒ์งธ ์ผ๊ณผ ๊ฒน์น์ง ์๋ ์์ ์์ ์ค์์์ ์ต๋ ์ด์ต์ ๋ํ๊ฑฐ๋
๊ทธ๋ ๋ค๋ฉด b์ ์ผ๊ณผ ๊ฒน์น์ง ์๋ ์์ ์์ ์ค ์ต๋์ด์ต์ ์ด๋ป๊ฒ ์ ์ ์์๊น?
๋ต๋ณ: ํ์ฌ ์์ ์ผ๊ณผ ๊ฒน์น์ง ์๋ ์์ ์ ๊ฐ์ฅ ์ต๊ทผ์ ๊ณ์ฐํ maxProfit ๊ฐ์ ์ฐพ์ผ๋ฉด ๋๋ค.
์ด์ : maxProfit์
ํ ์์ ์์ ์ ํํ ์ ์๋ ์ต๋ ์ด์ต์ด ๋์ ๋ ๋ฐฐ์ด
์ด๋ค. ๋ฐ๋ผ์ cur_Profit[i]
์ ๊ฒน์น์ง ์์ผ๋ฉด์๋ ๊ณ์ฐ์ด ์ ์ผ ์ต๊ทผ์ ๋๋ ๋ฐฐ์ด์ ์์๊ฐ ๊ณ ๋ฅผ ์ ์๋ ๊ฐ ์ค ์ต๋ ์ด์ต์ด ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ๊ณ์ฐ์ ๋ค์๊ณผ ๊ฐ์ด ์งํ๋๋ค.
(๋ง) maxProfit[maxProfit.length - 1]
๋ถํฐ maxProfit[0]
๊น์ง ์ญ์์ผ๋ก ์ฑ์ด๋ค. (๋ฐ๋ผ์ maxProfit[0]์๋ ๋ฌธ์ ์ ๋ต์ด ๊ธฐ๋ก๋ ๊ฒ์ด๋ค.)
(๋ฐ) ํ์ฌ ์์ ์์ ํ ์ ์๋ ์ผ์ ArrayList์์ ๊บผ๋ธ๋ค. (Job now = arrayList.get(i));
(์ฌ) ํด๋น ์์ ๊ณผ ์ ๊ฒน์น๋ฉด์ ๊ฐ์ฅ ์ต๊ทผ์ ํ๋ ์ผ์ด ์ธ์ ์ธ์ง ์์๋ธ๋ค.
(treeMap.ceilingEntry(now.e)
= ceilingEntry(Key)๋ Key ์ด์์ธ Key๊ฐ์ ๊ฐ์ง Entry ์ค Key์ ๊ฐ์ฅ ๊ฐ๊น์ด Entry๋ฅผ ๋ฐํ, ์ด๋ฅผ ํ์ฉํด์ ํ์ฌ ํ๋ ์ผ์ด ๋๋๋ ์์ ์์ ๊ฐ์ฅ ๊ฐ๊น์ด ์์ผ์ ์์ํ๋ ์ผ์ index
๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์)
(์) ์ ํ์์ ์งํํ๋ค.
(์) treeMap์ ํ์ฌ ์์ ์ ์ผ์ ์์ ์๊ฐ๊ณผ ๊ทธ index๋ฅผ ์ ์ด๋ฃ๋๋ค. ( ๋ค์ 7,8๋ฒ ๊ณ์ฐ์ ์ํด)
(3) ์ง์ ํด๋ณด๊ธฐโจ
a. ์ ์ผ ๋จผ์ ์ฌ์ฉํ๋ ๊ฒ๋ค์ check ํด๋์๋ค.
b, MaxProfit[4]๋ฒ ์์ ์์๋ ํ ์์ ์์ ํ ์ ์๋ ์ผ์ ํ๋ ๊ฒ์ด ์ต๋์ด์ต์ ๋ด๋ ๊ฒ์์ผ๋ก, ๊ทธ๋๋ก ์ผ์ํ๋ค.
maxProfit์ ์ฑ์๋ฃ์ ์ดํ, ํ ์์ ์ ์์์๊ฐ๊ณผ ๊ทธ index๋ฅผ TreeMap์ ์ฑ์๋ฃ๋๋ค. (์ดํ ๊ณ์ฐ์ ์ฌ์ฉํ๊ธฐ ์ํจ)
c. maxProfit[3]๋ฒ ์์ ์์๋ ์ด์ ๋ต ๋ต์ต(maxProfit[4]) : 60
, ํ ์์ ์ผ ํ๊ณ , ๊ทธ๊ฒ๊ณผ ์๊ฐ์ด ๊ฒน์น์ง ์๋ ์ ์์ ์ต๋ ์ด์ต ์ผํ๊ธฐ(cur_profit(3) + maxProfit[4]): 130
์์ผ๋ก ๋ ์ค ์ต๋๊ฐ์ธ 130์ ์ ํํ๋ค. MaxProfit[4]๊ฐ ๊ฒน์น์ง ์๋ ์ ์์ ์ต๋ ์ด์ต์ธ ์ด์ ๋ cur_Job์ ๋๋๋ ์๊ฐ์ด 6์ธ๋ฐ, maxProfit[4]์ ์์ ์๊ฐ์ด 6์ด๋ฏ๋ก, ๊ณ ๋ฅผ ์ ์๋ ์ต๋ ์ด์ต ์ค ๊ฐ์ฅ ์ต๊ทผ ๊ฐ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
์์์๋ ์ค๋ช
ํ๋ฏ์ด maxProfit[]์ด ๋์ ํฉ ๋ฐฐ์ด์ด๋ผ ์ต๊ทผ ๊ฐ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ด ์ต๋ ์ด์ต์ด๋ค.
d. ์ด์ ๊ฐ ๋ต์ต: 130
, ํ ์์ ์ผํ๊ณ , ๊ฒน์น์ง ์๋ ์ต๋ ์ด์ต ๊ฐ์ ธ์ค๊ธฐ: 100
์์ผ๋ก 130์ ํํ๋ค.
e. ์ด์ ๊ฐ ๋ต์ต: 130
, ํ ์์ ์ผํ๊ณ , ๊ฒน์น์ง ์๋ ์ต๋ ์ด์ต ๊ฐ์ ธ์ค๊ธฐ: 20 + 60 = 80
์ด๋ฏ๋ก, 130์ ๋ต์ตํ๋ค.
f. ์ด์ ๊ฐ ๋ต์ต: 130
, ํ ์์ ์ผํ๊ธฐ + ํ ์์ ์ผ๊ณผ ๊ฒน์น์ง ์๋ ์์ ์์ ์ต๋ ์ด์ต: 20 + 130 = 150
์ด๋ฏ๋ก 150์ ํํ๋ค.
๋ฐ๋ผ์ ๋ต์ 150์ด ๋๋ค.
3. ์ฝ๋ ์๊ฐ ๐
class Solution {
public int jobScheduling(int[] startTime, int[] endTime, int[] profit) {
// 0. ๋ณ์ ๋ชจ์
ArrayList<Job> schedules = new ArrayList<>(); // ๊ฐ ๋ชจ์ผ๊ธฐ (์์ ์๊ฐ ์์ผ๋ก ์ ๋ ฌ๋จ)
TreeMap<Integer, Integer> findNonOverLappingIndex = new TreeMap<>(); // <startTime, max_profit_index>: key๋ถํฐ ์์ํ ๋ ์ต๋ ์ด์ต
int [] maxProfits = new int[profit.length + 1]; // index = ํ์ฌ ํด์ผํ๋ ์ผ
// 1. ์ด๊ธฐํ
for(int i = 0; i < startTime.length; i ++){
schedules.add(new Job(startTime[i], endTime[i], profit[i]));
}
// 2. ๊ณ์ฐ
// (2-1) start ๊ธฐ์ค์ผ๋ก Job_schedules ์ ๋ฆฌ (์ค๋ฆ์ฐจ์)
Collections.sort(schedules, (o1,o2)-> o1.s - o2.s);
// 2. DP ์์, i = startTime
for(int i = startTime.length-1; i>= 0; i--){
Job now = schedules.get(i);
// ํ์ฌ ์กฐํ์ค์ธ ์ผ์ด ๋๋๋ ์๊ฐ๋ณด๋ค ๋ฆ๊ฒ ์์ํ๋ฉด์ ๊ฐ์ฅ ๊ฐ๊น์ด index๋ฅผ ์ฐพ๋๋ค. ์๋ค๋ฉด, MaxProfit[]์ ์ ์ผ ๋ง์ง๋ง index๋ฅผ ๋ฐํํ๋ค.
int nonOverLappingIndex = Optional.ofNullable(findNonOverLappingIndex.ceilingEntry(now.e)).map(e -> e.getValue()).orElse(maxProfits.length-1);
maxProfits[i] = Math.max(maxProfits[i+1], now.p + maxProfits[nonOverLappingIndex]);
// ๊ณ์ฐ์ด ๋๋๋ฉด, ํ์ฌ ๊ณ์ฐ์ด ๋๋ maxProfit์ index๋ฅผ TreeMap์ ๋ฃ๋๋ค.
findNonOverLappingIndex.put(now.s, i);
}
return maxProfits[0];
}
}
class Job {
int s;
int e;
int p;
public Job(int s, int e, int p) {
this.s = s;
this.e = e;
this.p = p;
}
public String toString() {
return s+"/"+e +"/" +p;
}
}
4. ๋ฐฐ์ด ๊ฒ๋ค ๐ฏ
(1) ์ TreeMap์ ArrayList ์ด๊ธฐํ ํ ๋ ๊ฐ์ด ์ด๊ธฐํ ์ํค์ง ์๋์?
๊ฒฐ๋ก : ๊ณ์ฐ์ด ๋๋ maxProfit์ index๋ง ์ ์ฅํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ๋์ ๊ณ์ฐ์ด ๋๋์ง ์์ maxProfit[]์ ๊ฐ์ด ์์ ์๊ฐ์ด ๋ ๋น ๋ฅด๋ค๋ ์ด์ ๋ก ์ ํ๋์ด ๊ณ์ฐ ์ค๋ฅ๋ฅผ ์ผ๊ธฐ ์ํค๊ธฐ ๋๋ฌธ์ด๋ค.