1235.规划兼职工作
思路:动态规划+二分查找。dp[i]表示在前i份工作里可选的最大薪水。我们先按工作结束时间升序排列,然后在for循环遍历到第i份工作时,考虑选它或者不选它。不选第i份工作,即dp[i]=dp[i-1];选第i份工作,需要找到结束时间都小于"第i份工作开始的时间"的工作数量。由于我们的遍历是按照工作结束时间升序进行遍历的。那么我们找到最后一个<="第i份工作开始的时间"的下标l,然后dp[i]=dp[l]+nd[i].p。最后选最大的状态转移方程dp[i]=max(dp[i-1],dp[l]+nd[i].p)即可。
class Solution {
public:
typedef struct Node{
int s,e,p;
bool friend operator<(struct Node a,struct Node b){
return a.e<b.e;
}
}node;
int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
int n=startTime.size();
node nd[50010];
nd[0]={0,0,0};//处理二分边界
for(int i=0;i<n;i++){
nd[i+1]={startTime[i],endTime[i],profit[i]};
}
sort(nd,nd+n+1);
int dp[50010];
dp[0]=nd[0].p;
for(int i=1;i<=n;i++){
int l=0,r=i-1;
while(l<r){
int mid=(l+r+1)/2;
if(nd[mid].e<=nd[i].s) l=mid;
else r=mid-1;
}
dp[i]=max(dp[i-1],dp[l]+nd[i].p);
}
return dp[n];
}
};
思考:在这里,如果dp[i]表示选第i份工作的最大薪水,那么我们就得遍历一遍“所有结束时间”小于“第i份工作开始时间”的工作,这样的话时间就会超时。所以在定义状态时,需要认真思考状态的含义。