zoukankan      html  css  js  c++  java
  • 差分法介绍

    原题

    我们计划在多个电商平台销售某件商品,给出n个不同的电商平台的该商品的售价区间,请给出该商品在所有电商平台的售价总和最高的最低商品定价。有如下示例,我们有3个平台的售价区间prices = {{7,9},{8,10},{9,10}},可以将商品定价在9元,商品总售价是9 * 3 = 27元,如下图所示

    image.png

    基本思路

    题目的意思是先保证总售价最高,在这个前提下使得商品的单价最低,比较直观的思路,建立一个hash表,unordered_map<int, int> price,表示某个price的平台数目,比如示例中price[7] = 1, price[8] = 2, price[9] = 3, price[10] = 1,然后将hash表中的键和值相乘,求最大值,如果有多个值相同,取键比较小的那个。本题目的难点在于如何以比较低的复杂度建立hash表,常规思路是(O(n^2)),可以参考下面的题目。

    参考题

    先看这道题,1109. 航班预订统计,有n 个航班,它们分别从 1 到 n 进行编号。我们这儿有一份航班预订表,表中第 i 条预订记录 bookings[i] = [i, j, k] 意味着我们在从 i j 的每个航班上预订了 k 个座位。请你返回一个长度为 n 的数组 answer,按航班编号顺序返回每个航班上预订的座位数。参考示例如下,

    输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
    输出:[10,55,45,25,25]
    

    解题思路

    将这道题的示例画一张表格表示一下,就是下面的结果

    booking 1 2 3 4 5
    1 10 10 0 0 0
    2 0 20 20 0 0
    3 0 25 25 25 25
    total 10 55 45 25 25

    常规思路就是以航班号为基本坐标,计算每一个航班增加的座位数,然后逐项汇总相加即可。

    1. 设置初始结果vector<int> res(n, 0);
    2. 遍历bookings,每次取其中的航班的预定数,添加到res对应的数组中,比如第1个booking,那么res[0]+=10; res[1]+=10,依次类推,直到遍历截止。

    上面的算法比较简单直观,但是可以分析发现,算法的复杂度有点高,两层遍历算法时间复杂度是(O(n^2)),空间复杂度是(O(n))不甚理想。

    有没有复杂度更简单的思路呢?这里有一个类比公交站的思路,可以将航班号码比作公交站牌,比如1号公交站,2号公交站,假定这些公交站是依次按顺序分布在一条直线公路上,i个航班的飞机的预定数目就是公交车在第i个公交站发车时候的乘客数目(包括了上车和下车的乘客数)。

    举例说明,第1行表示,第1站交车上人数是10,说明公交车行驶到第1站时上车10人,到第2站时候车上的乘客仍然是10人,说明没有乘客上下车,到第3站时候车上乘客0人,说明此时有10人下车。如果使用长度为N的数组count表示每一站上下乘客的变化量(count[i] 表示第i + 1站上下车的乘客变化量),

    对于booking = [i,j,k]

    1. 表示在公交站第i站上车k人,count[i - 1] += k
    2. i + 1站直到第j站都没有乘客上下车,count[i],...,count[j - 1]无操作;
    3. 在第j + 1站下车k人,所以count[j] -= k

    为了方便起见,我们缩小问题的规模,以具体的数字代替抽象的代数字母,假如我们就只有3个公交站,取示例中的前2行,

    1. 公交车刚开始上的人数是0,vector<int> count(4, 0)
    2. 读取第1行,到达第1站,公交车上10人,说明上车10人,无人下车,count[0]+= 10,到达第2站公交车上依然是10人,说明也无人上车和下车,到达第3站,公交车上0人,说明10人下车,count[2] -= 10
    3. 读取第2行,公交车到达第2站,公交车上20人,说明上车20人无人下车,count[1] += 20,第3站车上20人,说明无人下车,第4站车上0人,说明有20人下车, count[3]-=20

    遍历结束,得到count = {10, 20, -10,-20},那么最后每个站点的乘客数就很清楚了,到达第1站前车上乘客0人,到达后上车10人,所以第1站发车前车上10人,第2站到站后上车20人,所以第2站发车前车上乘客10 + 20 = 30人,第3站到站后下车10人,所以发车前车上乘客 30 - 10 = 20人。意思搞清楚之后,代码就很好写了。

    vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
            vector<int> res(n, 0);
            vector<int> counter(n + 1, 0);
            for (auto &booking : bookings)
            {
                int start = booking[0];
                int end = booking[1];
    			// 记录每个booking的开始和结尾即可,中间的站点人数无变化
                counter[start - 1] += booking[2]; // start站上车
                counter[end] -= booking[2]; // end + 1站下车
            }
            res[0] = counter[0];
            for (int i = 1; i < n; i++)
            {
                res[i] = res[i - 1] + counter[i];
            }
            return res;
        }
    

    时间复杂度为(O(n))

    原题代码

    借鉴参考题的代码,原题的代码如下

    int GetBestPrice(vector<vector<int>>& prices) {
    
        // find the minimum and maximum price
        int minVal = INT_MAX;
        int maxVal = INT_MIN;
        unordered_map<int, int> priceTable;
        for (auto& price : prices) {
            minVal = min(price[0], minVal);
            maxVal = max(price[1], maxVal); 
        }
        for (int i = minVal; i < maxVal + 1; i++) {
            priceTable[i] = 0;
        }  
        // counter[0]代表第minVal站,注意此处的对应关系
        int len = maxVal - minVal + 1;
        vector<int> counter(len + 1, 0);
    
        for (auto& price : prices)
        {
            int start = price[0] - minVal + 1;
            int end = price[1] - minVal + 1;
            
            counter[start - 1] += 1; // start站上车
            counter[end] -= 1; // end + 1站下车
        }
        
        priceTable[minVal] = counter[0];
        int bestPrice = minVal;
        maxVal = minVal * priceTable[minVal];
        for (int i = 1; i < len; i++)
        {
            priceTable[minVal + i] = priceTable[minVal + i - 1] + counter[i];
            if (priceTable[minVal + i] * (minVal + i) > maxVal) {
                maxVal = priceTable[minVal + i] * (minVal + i);
                bestPrice = minVal + i;
            }
        }
    
        return bestPrice;    
    }
    
  • 相关阅读:
    15.手写数字识别-小数据集(load_digits)
    14.深度学习-卷积
    13-垃圾邮件分类2
    12.朴素贝叶斯-垃圾邮件分类
    11.分类与监督学习,朴素贝叶斯分类算法
    9.主成分分析
    关于core_UI的安装和使用
    2020系统综合实践 期末大作业 15组
    2020系统综合实践 第7次实践作业 26组
    第6次实践作业
  • 原文地址:https://www.cnblogs.com/bugxch/p/13830754.html
Copyright © 2011-2022 走看看