|
62 | 62 |
|
63 | 63 | <!-- 这里可写通用的实现逻辑 -->
|
64 | 64 |
|
| 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 | + |
65 | 99 | <!-- tabs:start -->
|
66 | 100 |
|
67 | 101 | ### **Python3**
|
68 | 102 |
|
69 | 103 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
70 | 104 |
|
71 | 105 | ```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 | +``` |
72 | 120 |
|
| 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] |
73 | 131 | ```
|
74 | 132 |
|
75 | 133 | ### **Java**
|
76 | 134 |
|
77 | 135 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
78 | 136 |
|
79 | 137 | ```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 | +``` |
80 | 295 |
|
| 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 | +} |
81 | 319 | ```
|
82 | 320 |
|
83 | 321 | ### **...**
|
|
0 commit comments