Skip to content

Commit efb9582

Browse files
committed
feat: add solutions to lc problem: No.1235
No.1235.Maximum Profit in Job Scheduling
1 parent edeb912 commit efb9582

File tree

6 files changed

+520
-0
lines changed

6 files changed

+520
-0
lines changed

solution/1200-1299/1235.Maximum Profit in Job Scheduling/README.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,260 @@
6262

6363
<!-- 这里可写通用的实现逻辑 -->
6464

65+
**方法一:记忆化搜索 + 二分查找**
66+
67+
我们先将工作按照开始时间从小到大排序,然后设计一个函数 $dfs(i)$ 表示从第 $i$ 份工作开始,可以获得的最大报酬。答案即为 $dfs(0)$。
68+
69+
函数 $dfs(i)$ 的计算过程如下:
70+
71+
对于第 $i$ 份工作,我们可以选择做,也可以选择不做。如果不做,最大报酬就是 $dfs(i + 1)$;如果做,我们可以通过二分查找,找到在第 $i$ 份工作结束时间之后开始的第一份工作,记为 $j$,那么最大报酬就是 $profit[i] + dfs(j)$。取两者的较大值即可。即:
72+
73+
$$
74+
dfs(i)=\max(dfs(i+1),profit[i]+dfs(j))
75+
$$
76+
77+
其中 $j$ 是满足 $startTime[j] \ge endTime[i]$ 的最小的下标。
78+
79+
此过程中,我们可以使用记忆化搜索,将每个状态的答案保存下来,避免重复计算。
80+
81+
时间复杂度 $O(n \times \log n)$,其中 $n$ 是工作的数量。
82+
83+
**方法二:动态规划 + 二分查找**
84+
85+
我们还可以将方法一中的记忆化搜索改为动态规划。
86+
87+
先将工作排序,这次我们按照结束时间从小到大排序,然后定义 $dp[i]$,表示前 $i$ 份工作中,可以获得的最大报酬。答案即为 $dp[n]$。初始化 $dp[0]=0$。
88+
89+
对于第 $i$ 份工作,我们可以选择做,也可以选择不做。如果不做,最大报酬就是 $dp[i]$;如果做,我们可以通过二分查找,找到在第 $i$ 份工作开始时间之前结束的最后一份工作,记为 $j$,那么最大报酬就是 $profit[i] + dp[j]$。取两者的较大值即可。即:
90+
91+
$$
92+
dp[i+1] = \max(dp[i], profit[i] + dp[j])
93+
$$
94+
95+
其中 $j$ 是满足 $endTime[j] \leq startTime[i]$ 的最大的下标。
96+
97+
时间复杂度 $O(n \times \log n)$,其中 $n$ 是工作的数量。
98+
6599
<!-- tabs:start -->
66100

67101
### **Python3**
68102

69103
<!-- 这里可写当前语言的特殊实现逻辑 -->
70104

71105
```python
106+
class Solution:
107+
def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int:
108+
@cache
109+
def dfs(i):
110+
if i >= n:
111+
return 0
112+
_, e, p = jobs[i]
113+
j = bisect_left(jobs, e, lo=i + 1, key=lambda x: x[0])
114+
return max(dfs(i + 1), p + dfs(j))
115+
116+
jobs = sorted(zip(startTime, endTime, profit))
117+
n = len(profit)
118+
return dfs(0)
119+
```
72120

121+
```python
122+
class Solution:
123+
def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int:
124+
jobs = sorted(zip(endTime, startTime, profit))
125+
n = len(profit)
126+
dp = [0] * (n + 1)
127+
for i, (_, s, p) in enumerate(jobs):
128+
j = bisect_right(jobs, s, hi=i, key=lambda x: x[0])
129+
dp[i + 1] = max(dp[i], dp[j] + p)
130+
return dp[n]
73131
```
74132

75133
### **Java**
76134

77135
<!-- 这里可写当前语言的特殊实现逻辑 -->
78136

79137
```java
138+
class Solution {
139+
private int[][] jobs;
140+
private int[] f;
141+
private int n;
142+
143+
public int jobScheduling(int[] startTime, int[] endTime, int[] profit) {
144+
n = profit.length;
145+
jobs = new int[n][3];
146+
for (int i = 0; i < n; ++i) {
147+
jobs[i] = new int[] {startTime[i], endTime[i], profit[i]};
148+
}
149+
Arrays.sort(jobs, (a, b) -> a[0] - b[0]);
150+
f = new int[n];
151+
return dfs(0);
152+
}
153+
154+
private int dfs(int i) {
155+
if (i >= n) {
156+
return 0;
157+
}
158+
if (f[i] != 0) {
159+
return f[i];
160+
}
161+
int e = jobs[i][1], p = jobs[i][2];
162+
int j = search(jobs, e, i + 1);
163+
int ans = Math.max(dfs(i + 1), p + dfs(j));
164+
f[i] = ans;
165+
return ans;
166+
}
167+
168+
private int search(int[][] jobs, int x, int i) {
169+
int left = i, right = n;
170+
while (left < right) {
171+
int mid = (left + right) >> 1;
172+
if (jobs[mid][0] >= x) {
173+
right = mid;
174+
} else {
175+
left = mid + 1;
176+
}
177+
}
178+
return left;
179+
}
180+
}
181+
```
182+
183+
```java
184+
class Solution {
185+
public int jobScheduling(int[] startTime, int[] endTime, int[] profit) {
186+
int n = profit.length;
187+
int[][] jobs = new int[n][3];
188+
for (int i = 0; i < n; ++i) {
189+
jobs[i] = new int[] {startTime[i], endTime[i], profit[i]};
190+
}
191+
Arrays.sort(jobs, (a, b) -> a[1] - b[1]);
192+
int[] dp = new int[n + 1];
193+
for (int i = 0; i < n; ++i) {
194+
int j = search(jobs, jobs[i][0], i);
195+
dp[i + 1] = Math.max(dp[i], dp[j] + jobs[i][2]);
196+
}
197+
return dp[n];
198+
}
199+
200+
private int search(int[][] jobs, int x, int n) {
201+
int left = 0, right = n;
202+
while (left < right) {
203+
int mid = (left + right) >> 1;
204+
if (jobs[mid][1] > x) {
205+
right = mid;
206+
} else {
207+
left = mid + 1;
208+
}
209+
}
210+
return left;
211+
}
212+
}
213+
```
214+
215+
### **C++**
216+
217+
```cpp
218+
class Solution {
219+
public:
220+
int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
221+
int n = profit.size();
222+
vector<tuple<int, int, int>> jobs(n);
223+
for (int i = 0; i < n; ++i) jobs[i] = {startTime[i], endTime[i], profit[i]};
224+
sort(jobs.begin(), jobs.end());
225+
vector<int> f(n);
226+
function<int(int)> dfs = [&](int i) -> int {
227+
if (i >= n) return 0;
228+
if (f[i]) return f[i];
229+
auto [_, e, p] = jobs[i];
230+
tuple<int, int, int> t{e, 0, 0};
231+
int j = lower_bound(jobs.begin() + i + 1, jobs.end(), t, [&](auto& l, auto& r) -> bool { return get<0>(l) < get<0>(r); }) - jobs.begin();
232+
int ans = max(dfs(i + 1), p + dfs(j));
233+
f[i] = ans;
234+
return ans;
235+
};
236+
return dfs(0);
237+
}
238+
};
239+
```
240+
241+
```cpp
242+
class Solution {
243+
public:
244+
int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
245+
int n = profit.size();
246+
vector<tuple<int, int, int>> jobs(n);
247+
for (int i = 0; i < n; ++i) jobs[i] = {endTime[i], startTime[i], profit[i]};
248+
sort(jobs.begin(), jobs.end());
249+
vector<int> dp(n + 1);
250+
for (int i = 0; i < n; ++i) {
251+
auto [_, s, p] = jobs[i];
252+
int j = upper_bound(jobs.begin(), jobs.begin() + i, s, [&](int x, auto& job) -> bool { return x < get<0>(job); }) - jobs.begin();
253+
dp[i + 1] = max(dp[i], dp[j] + p);
254+
}
255+
return dp[n];
256+
}
257+
};
258+
```
259+
260+
### **Go**
261+
262+
```go
263+
func jobScheduling(startTime []int, endTime []int, profit []int) int {
264+
n := len(profit)
265+
type tuple struct{ s, e, p int }
266+
jobs := make([]tuple, n)
267+
for i, p := range profit {
268+
jobs[i] = tuple{startTime[i], endTime[i], p}
269+
}
270+
sort.Slice(jobs, func(i, j int) bool { return jobs[i].s < jobs[j].s })
271+
f := make([]int, n)
272+
var dfs func(int) int
273+
dfs = func(i int) int {
274+
if i >= n {
275+
return 0
276+
}
277+
if f[i] != 0 {
278+
return f[i]
279+
}
280+
j := sort.Search(n, func(j int) bool { return jobs[j].s >= jobs[i].e })
281+
ans := max(dfs(i+1), jobs[i].p+dfs(j))
282+
f[i] = ans
283+
return ans
284+
}
285+
return dfs(0)
286+
}
287+
288+
func max(a, b int) int {
289+
if a > b {
290+
return a
291+
}
292+
return b
293+
}
294+
```
80295

296+
```go
297+
func jobScheduling(startTime []int, endTime []int, profit []int) int {
298+
n := len(profit)
299+
type tuple struct{ s, e, p int }
300+
jobs := make([]tuple, n)
301+
for i, p := range profit {
302+
jobs[i] = tuple{startTime[i], endTime[i], p}
303+
}
304+
sort.Slice(jobs, func(i, j int) bool { return jobs[i].e < jobs[j].e })
305+
dp := make([]int, n+1)
306+
for i, job := range jobs {
307+
j := sort.Search(i, func(k int) bool { return jobs[k].e > job.s })
308+
dp[i+1] = max(dp[i], dp[j]+job.p)
309+
}
310+
return dp[n]
311+
}
312+
313+
func max(a, b int) int {
314+
if a > b {
315+
return a
316+
}
317+
return b
318+
}
81319
```
82320

83321
### **...**

0 commit comments

Comments
 (0)