力扣1235(销售利润最大化)-DP-二分-排序

2830. 销售利润最大化

1. 题目描述

给你一个整数 n 表示数轴上的房屋数量,编号从 0 到 n - 1 。

另给你一个二维整数数组 offers ,其中 offers[i] = [starti, endi, goldi] 表示第 i 个买家想要以 goldi 枚金币的价格购买从 starti 到 endi 的所有房屋。

作为一名销售,你需要有策略地选择并销售房屋使自己的收入最大化。

返回你可以赚取的金币的最大数目。

注意 同一所房屋不能卖给不同的买家,并且允许保留一些房屋不进行出售。

2. 思路

DP+排序+二分

2.1. DP思路

DP两大思考方向:

  • 选或不选(遍历到某个offer时选择卖或者不卖)
  • 枚举(如果卖,枚举之前的offer,选出与当前offer不冲突的offer)

首先将offersend(题中的offers[][1])从小到大排序

dp[i]代表总共有ioffer时,收入的最大值。dp[n-1]即为题目所求

状态方程:dp[i] = max{dp[i-1], dp[j]+offers[i][2]} , j满足0<=j<i,且offers[j][1]<offers[i][0]

dp[i-1]是指不卖第ioffer中所包含范围内的房子,dp[j]+offers[i][2]是指卖第ioffer中所包含范围内的房子,但要找到不冲突的offeroffers[j][1]<offers[i][0]是冲突判断。

因为dp[i-1]一定比dp[i]小或者相等,所以只需寻找满足offers[j][1]<offers[i][0]的最大下标j即可

伪代码:


    int maximizeTheProfit(int n, vector<vector<int>>& offers) {
        sort(offers.begin(), offers.end(), cmp);
        int dp[100010]={0};
        dp[0] = offers[0][2]; 
        for(int i=1;i<offers.size();i++){
        	在[0,i-1]范围内寻找不冲突的最大下标index
            dp[i] = max(dp[i-1], offers[i][2]+dp[index]);
        }
        return dp[offers.size()-1];
    }
2.2 二分优化

寻找满足offers[j][1]<offers[i][0]的最大下标j
先用二分寻找第一个满足offers[j][1]>=offers[i][0]的下标j,那么j-1即时所求

二分代码:

int binarySearch(vector<vector<int>>& x, int target, int l, int r) {
        // 找大于等于target的第一个数
        while(l<=r){
            int mid = (l+r)/2;
            if(x[mid][1]<target){
                l=mid+1;
            }else{
                r=mid-1;
            }
        }
        return l;
    }

二分搜索详解

2.3 c++ upper_bound/lower_bound使用(重点学习)

c++ upper_bound/lower_bound

3. 代码

class Solution {
public: 
    
    static bool cmp(vector<int>& x,vector<int>& y) {
        if(x[1] == y[1])return x[0] < y[0];
        return x[1] < y[1];
    }
    int binarySearch(vector<vector<int>>& x, int target, int l, int r) {
        // 找大于等于target的第一个数
        while(l<=r){
            int mid = (l+r)/2;
            if(x[mid][1]<target){
                l=mid+1;
            }else{
                r=mid-1;
            }
        }
        return l;
    }
    int maximizeTheProfit(int n, vector<vector<int>>& offers) {
        sort(offers.begin(), offers.end(), cmp);
        int dp[100010]={0};
        dp[0] = offers[0][2]; 
        for(int i=1;i<offers.size();i++){
            int index = binarySearch(offers, offers[i][0], 0, i-1);
            index--; // index offers[j][1]小于offers[i][0]的最大下标
            int tmp = index!=-1?dp[index]:0;
            dp[i] = max(dp[i-1], offers[i][2]+tmp);
            printf("index:%d dp[i]:%d\n", index, dp[i]);
        }
        return dp[offers.size()-1];
    }
};

4. 同类型题

lc1235. 规划兼职工作
lc2008. 出租车的最大盈利

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值