leetcode 1235. 规划兼职工作

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-profit-in-job-scheduling
著作权归领扣网络所有。

你打算利用空闲时间来做兼职工作赚些零花钱。
这里有 n 份兼职工作,每份工作预计从 startTime[i] 开始到 endTime[i] 结束,报酬为 profit[i]。
给你一份兼职工作表,包含开始时间 startTime,结束时间 endTime 和预计报酬 profit 三个数组,请你计算并返回可以获得的最大报酬。
注意,时间上出现重叠的 2 份工作不能同时进行。
如果你选择的工作在时间 X 结束,那么你可以立刻进行在时间 X 开始的下一份工作。

示例 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:

输入: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:

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

动态规划视频

https://www.bilibili.com/video/BV18x411V7fm

遇到的问题

最开始没有根据结束时间排序,写出的代码的结果发现:
示例2=120
示例3=4
之后有看了一遍视频,发现元素是先结束时间从早到晚排列(主排序),再按开始时间的从早到晚排序(次排序)

加上排序后的完整代码

#include <stdio.h>
#include <stdlib.h>

typedef struct profitNode {
    int startTime;
    int endTime;
    int profit;
} profitNode;

void print_array(int *a, int len) {
    for (int i = 0; i < len; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
}

int cmp(const void * a, const void * b) {
    profitNode *A = (profitNode *)a;
    profitNode *B = (profitNode *)b;

    if ( A->endTime == B->endTime ) {
        return A->startTime - B->startTime;
    } else {
        return A->endTime - B->endTime;
    }
}

void sortByEndTimeAscStartTimeAsc(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int* profit, int profitSize) {
    profitNode * new = (profitNode *)calloc(startTimeSize, sizeof(profitNode));
    for ( int i = 0; i < startTimeSize; i++ ) {
        new[i].startTime = startTime[i];
        new[i].endTime = endTime[i];
        new[i].profit = profit[i];
    }
    qsort(new, startTimeSize, sizeof(profitNode), cmp);
    for ( int i = 0; i < startTimeSize; i++ ) {
        startTime[i] = new[i].startTime;
        endTime[i] = new[i].endTime;
        profit[i] = new[i].profit;
    }
    free(new);
}

int *getPrev(int* startTime, int startTimeSize, int* endTime, int endTimeSize) {
    int *prev = (int *) calloc(startTimeSize, sizeof(int));
    for ( int i = 0; i < startTimeSize; i++ ) {
        prev[i] = -1;
        for ( int j = i-1; j >= 0; j-- ) {
            if ( startTime[i] >= endTime[j] ) {
                prev[i] = j;
                break;
            }
        }
    }

    return prev;
}

int jobScheduling(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int* profit, int profitSize){
    //先排序
    sortByEndTimeAscStartTimeAsc(startTime, startTimeSize, endTime, endTimeSize, profit, profitSize);
    int *prev = getPrev(startTime, startTimeSize, endTime, endTimeSize);
    int *opt = (int *) calloc(profitSize, sizeof(int));
    // opt[i] = max( profit[i] + opt(prev[i]), opt(i-1))

    for (int i = 0; i < profitSize; i++) {
        //不选i的价值
        int notSelect = i-1 >= 0 ? opt[i-1] : 0;
        //选i的价值
        int select = prev[i] >= 0 ? profit[i] + opt[prev[i]] : profit[i];

        opt[i] = notSelect > select ? notSelect : select;
    }
    print_array(prev, profitSize);
    print_array(opt, profitSize);
    
    return opt[profitSize-1];
}

int main() {
    // int size = 3;
    // int startTime[] = {1,1,1}, endTime[] = {2,3,4}, profit[] = {5,6,4};
    // int size = 4;
    // int startTime[] = {1,2,3,3}, endTime[] = {3,4,5,6}, profit[] = {50,10,40,70};
    int size = 5;
    int startTime[] = {1,2,3,4,6}, endTime[] = {3,5,10,6,9}, profit[] = {20,20,100,70,60};
    int maxProfit = jobScheduling(startTime, size, endTime, size, profit, size);
    printf("%d\n", maxProfit);

    return 0;
}

/**
size=4的 示例1的执行过程
prev = -1 -1 0 0
opt  = 50 50 90 120 
maxProfit = 120

size=3的 示例3的执行过程
prev = -1 -1 -1
opt  = 5 6 6 
maxProfit = 6

size=5的 示例2的执行过程
prev = -1 -1 0 2 0 
opt  = 20 20 90 150 150 
maxProfit = 150
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值