抄书问题之二

Given n books( the page number of each book is the same) and an array of integer with size k means k people to copy the book and the i th integer is the time i th person to copy one book). You must distribute the continuous id books to one people to copy. (You can give book A[1],A[2] to one people, but you cannot give book A[1], A[3] to one people, because book A[1] and A[3] is not continuous.) Return the number of smallest minutes need to copy all the books.

样例

Given n = 4, array A = [3,2,4], .

Return 4( First person spends 3 minutes to copy book 1, Second person spends 4 minutes to copy book 2 and 3, Third person spends 4 minutes to copy book 4. )


解题思路:

1.二分法,最优解。

2 动态规划,时间复杂度很高O(N2 × K)。

class Solution {
public:
    /**
     * @param n: an integer
     * @param times: a vector of integers
     * @return: an integer
     */
    // V1 二分法 (最优解)
    int copyBooksII(int n, vector<int> ×) {
        if(n == 0){
            return 0;
        }
        int k = times.size();
        if(k == 0){
            return numeric_limits<int>::max();
        }
        else if (k == 1){
            //只有一个抄书员
            return times[0] * n;
        }
        //找出抄书时间的上下限
        // 所有人以最快速度抄书,得到下限
        // 所有人以最慢速度抄书,得到上限
        int lowBound = numeric_limits<int>::max();
        int highBound = numeric_limits<int>::min();
        for(int i = 0; i < k; i++){
            lowBound = min(lowBound, times[i]);
            highBound = max(highBound, times[i]);
        }
        lowBound =  lowBound * (( n + k - 1) / k);
        highBound = highBound * (( n + k - 1) / k);
        
        // 这里需要排序,将速度最快的排在前面,这样便于canCopy判断
        sort(times.begin(), times.end());
        
        // 二分法找出答案,每次二分时判断间值是否能在target时间内抄完
        while(lowBound < highBound){
            int mid = lowBound + (highBound - lowBound)/2;
            if(canCopy(mid, n, times)){
                highBound = mid;
            }
            else{
                lowBound = mid + 1;
            }
        }
        return lowBound;
    }
    // 判断是否能在target时间内抄写完成
    // 优先选择最快的人抄写,因此事前需要对times 排序。
    // 抄写速度最快的人尽量多抄
    bool canCopy(int target, int n, vector<int> ×){
        int totalBookCount = n;
        int sum = 0;
        int i = 0;
        while(i < times.size()){
            if(sum + times[i] <= target){
                sum += times[i];
            }
            else if (i != (times.size() - 1) && 
                     times[++i] <= target){
                sum = times[i];
            }
            else {
                return false;
            }
            
            totalBookCount--;
            
            if(totalBookCount <= 0){
                return true;
            }
        }
        return false;
    }
    //
    /
    // V2 : DP, time limit exceeded O(N2 * K)
    int copyBooksII1(int n, vector<int> ×) {
        // write your code here
        if(n == 0){
            return 0;
        }
        int k = times.size();
        if(k == 0){
            return numeric_limits<int>::max();
        }
        else if (k == 1){
            //只有一个抄书员
            return times[0] * n;
        }
        //f[i][j] 表示i个人抄j本书的最小耗时
        vector<vector<int> > f(k+1, vector<int>(n+1, 0));
        for(int j = 1; j <= n; j++){
            f[0][j] = numeric_limits<int>::max();
            f[1][j] = times[0] * j;
        }
        for(int i = 1; i <= k; i++){
            for(int j = 1; j <= n; j++){
                int minTime = numeric_limits<int>::max();
                for(int x = 0; x <= j; x++){
                    minTime = min(minTime,
                                  max(f[i-1][x], (j - x) * times[i-1]));
                }
                f[i][j] = minTime;
            }
        }
        return f[k][n];
    }
    //V3 : DP 优化, 滚动数组空间优化,但是时间复杂度仍然比较高
    int copyBooksII2(int n, vector<int> ×) {
        // write your code here
        if(n == 0){
            return 0;
        }
        int k = times.size();
        if(k == 0){
            return numeric_limits<int>::max();
        }
        else if (k == 1){
            //只有一个抄书员
            return times[0] * n;
        }
        //f[i][j] 表示i个人抄j本书的最小耗时
        vector<vector<int> > f(2, vector<int>(n+1, 0));
        for(int j = 1; j <= n; j++){
            f[0][j] = numeric_limits<int>::max();
        }
        for(int i = 1; i <= k; i++){
            for(int j = 1; j <= n; j++){
                int minTime = numeric_limits<int>::max();
                for(int x = j; x >= 0; x--){
                    minTime = min(minTime,
                                  max(f[(i-1)%2][x], (j - x) * times[i-1]));
                    
                    if(f[(i-1)%2][x] < (j - x) * times[i-1]){
                        break;
                    }
                    
                }
                f[i%2][j] = minTime;
            }
        }
        return f[k%2][n];
    }
    
};




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值