Sunday, July 19, 2015

Copy Books @Lintcode

Given an array A of integer with size of n( means n books and number of pages of each book) and k people to copy the 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.) Each person have can copy one page per minute. Return the number of smallest minutes need to copy all the books.

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. )
很明显地用dp来做。dp[i][j] 代表前i本书由j个工作者完成需要的最小时间。状态转移方程如下:
dp[i+1][j+1] = Min(Max(dp[i][k], A[k]+...+A[j+1])),  where k from i to j+1
意思就是每加入一个新worker的时候,从后往前累加他需要copy的book,每次更新总体所需要的时间;而总体需要的时间是之前所有worker分配方案中的最优时间和新worker所需时间两者中的较大值。

时间复杂度 O(N^2*k), 暂时没想到 O(N*k) 的方法 :( 麻烦各路大神指点。。。
public int copyBooks(int[] pages, int k) {
// write your code here
int[][] dp = new int[k+1][pages.length+1];
int sum = 0;
int max = 0;
for(int i=1; i<=pages.length; i++){
sum += pages[i-1];
dp[1][i] = sum;
max = Math.max(max, pages[i-1]);
}
if(k>=pages.length){
return max;
}
for(int i=2; i<=k; i++){
for(int j=pages.length-1; j>=i-1; j--){
int current = pages[j];
int min = Math.max(pages[j], dp[i-1][j]);
dp[i][j+1] = min;
for(int l=j-1; l>=i-1; l--){
current += pages[l];
int curMin = Math.max(current, dp[i-1][l]);
if(curMin<min){
dp[i][j+1] = curMin;
min = curMin;
}
}
}
}
return dp[k][pages.length];
}
view raw gistfile1.txt hosted with ❤ by GitHub

5 comments:

  1. O(n * k) solution http://sidbai.github.io/2015/07/25/Copy-Books/

    ReplyDelete
  2. dp[i][j] 代表前j本书由i个工作者完成需要的最小时间?

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. dp[i][j] 应该表示的是 前 j 本书 由 i 个工作者完成所需最小时间

    ReplyDelete

Leetcode 316. Remove Duplicate Letters

 这道题表面问的是如何删除重复,实际在问如何从多个字符选取一个保留,从而让整个字符串按升序排列。那么策略就是对于高顺位的字符比如‘a',就要选靠前位置的保留,而低顺位字符如’z'则应该尽量选取靠后位置保留。 算法大概思路:每看到一个字符,我们要决定是否保留 1. ...