算法-书籍复印(二分法)

今天在lintCode又做了一道关于非常规二分法的使用,觉得还是有必要记录下来。

题意:

给出一个数组A包含n个元素,表示n本书以及各自的页数。现在有个k个人复印
书籍,每个人只能复印连续一段编号的书,比如A[1],A[2]由第一个人复印,但
是不能A[1],A[3]由第一个人复印,求最少需要的时间复印所有书。

样例:

A = [3,2,4],k = 2

返回5,第一个人复印前两本书

这个题看上去感觉好难的样子,但是实际上,这个题非常的简单,就是一个二分法定区间的题。这种题在这之前,我也写了两篇关于非常规二分法使用的博客,相对来说,还是比较类似的。

1.解题思路

首先,我们假设只有一个人在复印书籍,那么使用的时间就是所有的书籍页数总和,我们假设是sum,如果有无数个人在复印书籍的话(实际上,我们看做是人数与书的数目相等,不是书的页数),那么使用的时间就是书籍的最大页数,我假设是max。因此,我们得出结论,k个人在复印书籍的话,使用的时间肯定在[max, sum]。

所以,我们可以在[max,sum]的区间上不断的二分,不断的缩小范围。其中方法是这样,我们计算出 mid = (start + end) /2(假设start  = max, end = sum),然后计算出当最大页数是mid时,需要的人数,我们假设为count,如果count大于k的话,那么表示如果k个人复印mid页的话是不够的,如果需要增加每个人的复印页数(这个页数肯定在(mid, end]区间),因此start = mid;反之,表示每个人复印mid页印多了,k个人中有人可以不需要印,所以我们需要减少每个人的复印页数(这个页数肯定在[start,mid))。

但是这里有一个问题,就是这个二分的结束条件。之前的二分结束条件几乎都是 start < end,但是在这里却不一样了,因为如果结束还是那样的话,那么有可能出现死循环。例如:

因此,在这里二分的结束条件不能设置为 start < mid, 应该是Start + 1 < mid。在最后的时候在计算一次,如果在start的情况下,count <= k,则返回start, 反之返回end。

2.代码

 1     public static int copyBooks(int[] pages, int k) {
 2         if (pages == null || pages.length == 0 || k == 0) {
 3             return 0;
 4         }
 5
 6         int max = Integer.MIN_VALUE;
 7         int sum = 0;
 8         //计算最大值和总和
 9         for (int i : pages) {
10             if (i > max) {
11                 max = i;
12             }
13             sum += i;
14         }
15         int start = max;
16         int end = sum;
17         //二分
18         while (start + 1 < end) {
19             int mid = (end - start) / 2 + start;
20
21             if (countCopier(pages, mid) > k) {
22                 start = mid;
23             } else {
24                 end = mid;
25             }
26         }
27         return start;
28     }
29     //计算在每个人复印limit页数的情况下,需要的人数
30     private static int countCopier(int pages[], int limit) {
31         int sum = pages[0];
32         int copierCount = 1;
33         for (int i = 0; i < pages.length; i++) {
34             if(sum + pages[i] > limit) {
35                 copierCount++;
36                 sum = 0;
37             }
38             sum += pages[i];
39         }
40         return copierCount;
41     }
时间: 2024-10-05 23:26:14

算法-书籍复印(二分法)的相关文章

推些C语言与算法书籍

c语言系统学习与进阶: 1. C primer plus C primer plus 作为一本被人推崇备至的 c 入门经典,C primer plus 绝非浪得虚名.应该 算得上 C 教材里最好的入门书了.    在知识广度上,很少有书能匹及.它能为你系统学习 c 提供一个良好的平台.作者对 c 的见解精辟.在娓娓叙述的同时,作者辅以大量程序以分析.它让我对 C 有了更加系统的全 新认识.决非国人所写的那些公理化的教条说教,我觉得作者把自己的心血全部吐露.书很 厚,近 700 页,却不没有让我觉

Python函数练习:冒泡算法+快速排序(二分法)

冒泡算法: #-*- coding: UTF-8 -*-#冒泡排序 def func(lt): if type(lt).__name__ !='list' and type(lt).__name__ !='tuple': return if type(lt).__name__ == 'tuple': return list(lt) for i in range(1,len(lt)-1): for j in range(1,len(lt)-i): if lt[j] > lt[j+1]: lt[j]

iOS 排序算法总结、二分法查找

还有一个:二分插入排序  平均时间O(n2)   稳定 1.插入排序 在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的.如此反复循环,直到全部排好顺序. 直接插入排序是稳定的.算法时间复杂度O(n2)--[n的平方] main() { int  a[10],j,i,m; for(j=1;j<10;j++) { m=a[j]; for(i=j-1;i>=0;i--) { if(a[i]<m) b

矿Java开发学习之旅------&amp;gt;Java排序算法经典的二分法插入排序

一.折半插入排序(二分插入排序) 将直接插入排序中寻找A[i]的插入位置的方法改为採用折半比較,就可以得到折半插入排序算法.在处理A[i]时,A[0]--A[i-1]已经按关键码值排好序.所谓折半比較,就是在插入A[i]时,取A[i-1/2]的关键码值与A[i]的关键码值进行比較,假设A[i]的关键码值小于A[i-1/2]的关键码值.则说明A[i]仅仅能插入A[0]到A[i-1/2]之间.故能够在A[0]到A[i-1/2-1]之间继续使用折半比較:否则仅仅能插入A[i-1/2]到A[i-1]之间

数据结构和算法-005 数组排序 二分法检索

二分法检索 二分法检索(binary search)又称折半检索,二分法检索的基本思想是设字典中的元素从小到大有序地存放在数组(array)中, 首先将给定值key与字典中间位置上元素的关键码(key)比较,如果相等,则检索成功: 否则,若key小,则在字典前半部分中继续进行二分法检索; 若key大,则在字典后半部分中继续进行二分法检索. 这样,经过一次比较就缩小一半的检索区间,如此进行下去,直到检索成功或检索失败. 偶数个取中间2个其中任何一个作为中间元素 二分法检索是一种效率较高的检索方法,

数据结构和算法之:二分法demo

package com.js.ai.modules.pointwall.testxfz; class OrdArray{ private long[] a; private int nElems; public OrdArray(int max) { a=new long[max]; nElems=0; } public int size(){ return nElems; } //插入方法 public void insert(long value){ int j; for(j=0;j<nEl

成正态分布的查找算法(优化二分法)

  在一个有序静态表中查找某个数值,其表中概率呈现正态分布,但是数据的中心却不是在数据的中点取得,如何得到最优算法.代码如下://判断是否在这个区间函数 bool check(int number) void callfunction(int min,int max) {  int temp=0;//中间变量  bool flag=check(max);     while(flag)  {   min=max;   max=2*min;  }  while(min<max)  {   temp

我的算法学习之路

关于 严格来说,本文题目应该是我的数据结构和算法学习之路,但这个写法实在太绕口--况且CS中的算法往往暗指数据结构和算法(例如算法导论指的实际上是数据结构和算法导论),所以我认为本文题目是合理的. 这篇文章讲了什么? 我这些年学习数据结构和算法的总结. 一些不错的算法书籍和教程. 算法的重要性. 初学 第一次接触数据结构是在大二下学期的数据结构课程.然而这门课程并没有让我入门--当时自己正忙于倒卖各种MP3和耳机,对于这些课程根本就不屑一顾--反正最后考试划个重点也能过,于是这门整个计算机专业本

与Javascript相关的数据结构和算法

著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:豪情链接:http://www.zhihu.com/question/36882354/answer/69416260来源:知乎 建议先打好基础,了解js语言的特性或玩法,然后再来玩算法,个人感觉才能四两拨千斤,算法这种东西,是高级抽象的东西,简单说:是熟悉计算机语言解决日常需求的前提下,熟练的选择一种高效的做事方式,先了解如何将日常的需求或人类的自然语言转换为计算机语言,然后在进一步的确定算法在整个代码开发中所扮演的角色