leetCode 1235. 规划兼职工作 [动态规划+二分查找]

目录

1.需要知识

1.1 sort自定义排序

1.2 upper_bound()

2. 题目

3. 思路 

4. 代码实现

5. 后记


1.需要知识

1.1 sort自定义排序


sort函数有三个参数:
sort(start, end, compare);

    start为需要排序区域的起点;
    end为需要排序区域的终点;
    compare为排序方式,可以不指定,此时默认为升序排列。(ps:这个也可以我们自行定义)

如果要自行定义的话,如下:

​
//自定义的compare函数,按照结束时间早晚升序排序
bool lessSort(array a,array b){return a[1] < b[1];}
class Solution {
public:
    int jobScheduling(vector& startTime, vector& endTime, vector& profit) {
       int n = startTime.size();
       array res[n];
       for(int i = 0;i

还有一个关于自定义的compare函数(也就是我上面的lessSort函数)要注意的点:

sort的第三个参数是一个函数指针,如果将自定义的compare函数放在类里面,那么此时compare是一个非静态函数指针,会报错。
需要将compare()函数的声明加static关键字或者将函数移到类外即可

1.2 upper_bound()

upper_bound() 函数定义在头文件中,用于在指定范围内查找大于(没有等于!!!)目标值的第一个元素(使用二分查找法)。该函数的语法格式有 2 种,分别是:

//查找[first, last)区域中第一个大于 val 的元素。
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,
                             const T& val);
//查找[first, last)区域中第一个不符合 comp 规则的元素
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,
                             const T& val, Compare comp);

其中,

  • first 和 last 都为正向迭代器,[first, last) 用于指定该函数的作用范围;
  •  val 用于执行目标值;
  • comp 用于自定义查找规则:此函数中可接收一个包含 2 个形参(第一个形参值始终为 val)且返回值为 bool 类型的函数,可以是普通函数,也可以是函数对象。

意思也就是说,在使用自定义的comp函数比较中,comp(val,比较的数组中的值)

举例:

​
bool compaire(int a, int b) { return a < b; }//升序排序

int main() {

        int a[10] = { 2,2,3,4,5,6,7,8,9,10 };
// 使用自定义compaire比较,那么在比较中就是compaire(1,a[i])   其中1也就是传入的val值
        cout << upper_bound(a, a + 9, 1,compaire)-a << endl;
        return 0;

}

​

输出结果:

0

因为相当于 1和2,2,3,4,5,6,7,8,9比较,得到 a[0] = 2 > 1 是第一个 >1 的元素

注:最后upper_bound返回的是一个指向找到元素的指针,如果一直没找到,就会返回指向最后一个查找元素的指针

2. 题目

你打算利用空闲时间来做兼职工作赚些零花钱。

这里有 n 份兼职工作,每份工作预计从 startTime[i] 开始到 endTime[i] 结束,报酬为 profit[i]

给你一份兼职工作表,包含开始时间 startTime,结束时间 endTime 和预计报酬 profit 三个数组,请你计算并返回可以获得的最大报酬。

注意,时间上出现重叠的 2 份工作不能同时进行。

如果你选择的工作在时间 X 结束,那么你可以立刻进行在时间 X 开始的下一份工作。

示例 1:

leetCode 1235. 规划兼职工作 [动态规划+二分查找]_第1张图片

输入:startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70]
输出:120
解释:
我们选出第 1 份和第 4 份工作, 
时间范围是 [1-3]+[3-6],共获得报酬 120 = 50 + 70。

示例 2:

leetCode 1235. 规划兼职工作 [动态规划+二分查找]_第2张图片

输入:startTime = [1,2,3,4,6], endTime = [3,5,10,6,9], profit = [20,20,100,70,60]
输出:150
解释:
我们选择第 1,4,5 份工作。 
共获得报酬 150 = 20 + 70 + 60。

示例 3:

leetCode 1235. 规划兼职工作 [动态规划+二分查找]_第3张图片

输入:startTime = [1,1,1], endTime = [2,3,4], profit = [5,6,4]
输出:6s

3. 思路 

  1. 将所有的兼职工作按照结束时间早晚排列
  2. 利用动态规划,选择当前的兼职工作是加入还是不加入;
  • 加入:找到最近的结束在当前的兼职活动开始前的活动(before),那么加入当前兼职工作后的收益就是dp [before] +  profit[current] 
  • 不加入:当前收益是上一个兼职工作的收益(注意:不是上述加入中的before兼职工作的收益,而是排序中的上一个兼职工作)

      比较加入和不加入的收益大小,取大的加入dp数组中记录 

也就是

     dp[ current ] = max ( dp [current-1] , dp [before]  +  profit [current] )

但是程序中是从下标0开始遍历兼职活动的,所以为了处理 0 元素使用 dp 时出现下标 -1 的情况,将dp中的元素都统一 +1,赋值dp[0] 为0,并且这样以后,所有没有上一个兼职活动的活动,也就是

endTime[before] <= startTime[current]  的元素个数为0个

那么使用upper_bound()查找的时候,就会返回第一个元素的编号,也就是0,(不明白的小可爱可以看看上面upper_bound()的例子)但我们处理过dp[0] = 0,那么这一类的活动就都会有一个dp[0] = 0 的收益,不需要进行特殊情况处理

4. 代码实现

​
bool lessSort(array a,array b){return a[1] < b[1];}//升序排序
class Solution {
public:
    int jobScheduling(vector& startTime, vector& endTime, vector& profit) {
       int n = startTime.size();
//array res[n]     存放兼职活动的数组,每个兼职活动中有3个元素,为开始时间,结束时间和收益
       array res* = new array[n];
       int dp* = new int[n];
       for(int i = 0;i{0,res[i][0],0},lessSort)-res;
          dp[i+1] = max(dp[i],dp[r]+res[i][2]);
       }
       return dp[n];
    }
};

​

5. 后记

在查看大家题解的时候,还发现了一种很有意思的sort中compare的写法,记录一下:

//这样写就不需要再写上面的lessSort函数了
sort(jobs, jobs + n, [](auto &a, auto &b) { return a[1] < b[1]; }); // 按照结束时间排序

你可能感兴趣的:(leetCode,leetcode,c++)