437. Copy Books

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lighthear/article/details/79416420

Description

Given n books and the ith book has A[i] pages. You are given k people to copy the n books.

n books list in a row and each person can claim a continous range of the n books. For example one copier can copy the books from ith to jth continously, but he can not copy the 1st book, 2nd book and 4th book (without 3rd book).

They start copying books at the same time and they all cost 1 minute to copy 1 page of a book. What's the best strategy to assign books so that the slowest copier can finish at earliest time?

Example

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

Return 5( First person spends 5 minutes to copy book 1 and book 2 and second person spends 4 minutes to copy book 3. )

Solution

分割问题多用动态规划解决,但是本题也可以采用二分法解决。

1. 二分法:

本题应将工作量进行二分查找,二分法的起始位置应选取start = max(pages)以保证一个人至少可以独立抄完一本书,结束位置为一个人抄完所有书,即total = sum(pages)。判断条件是是否超过规定人数,如果超过则增大任务量,否则减少任务量,从而逐渐缩小任务量范围。

Java

public class Solution {
    /**
     * @param pages: an array of integers
     * @param k: An integer
     * @return: an integer
     */
    public int copyBooks(int[] pages, int k) {
        // write your code here
        //一句话描述题意:将数组切分为k个子数组,让数组和最大的最小
        //采用二分法
        if (pages == null || pages.length == 0) {
            return 0;
        }
        
        int total = 0;
        int max = pages[0];
        for (int i = 0; i < pages.length; i++) {
            total += pages[i];
            if (max < pages[i]) {
                max = pages[i];
            }
        }
        //start从max开始,保证每人至少能抄完一本书,end取total,极端情况一个人抄了所有的书
        int start = max;
        int end = total;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (countCopiers(pages, mid) > k) {
                //如果人数太多了就增大工作量,将start右移
                start = mid;
            } else {
                //否则说明人不够或者刚好,则减少工作量,将end左移
                end = mid;
            }
        }
        if (countCopiers(pages, start) <= k) {
            //若较小的任务量能满足人数要求,则返回较小的任务量
            return start;
        } else {
            //若小任务量需求的人太多,就返回较大的任务量
            return end;
        }
    }
    //计算每人抄limit本书时,至少需要几个人
    private int countCopiers(int[] pages, int limit) {
        if (pages == null || pages.length == 0) {
            return 0;
        }
        int copiers = 1;
        int sum = 0;
        for (int i = 0; i < pages.length; i++) {
            if (sum + pages[i] > limit) {
                //如果超过工作量,就增加抄写员,并且清空sum
                copiers++;
                sum = 0;
            }
            //将当前的书加入sum,如果刚刚超过工作量,则这本书就是下一个人的工作量,如果没超过则可以继续累加这本
            sum += pages[i];
        }
        return copiers;
    }
}

猜你喜欢

转载自blog.csdn.net/lighthear/article/details/79416420
今日推荐