[牛客題霸-高頻算法面試題]同樣的水

題目描述

有n個水桶,第i個水桶裏面水的體積爲Ai,你能夠用1秒時間向一個桶裏添加1體積的水。數組

有q次詢問,每次詢問一個整數pi,你須要求出使其中pi個桶中水的體積相同所花費的最少時間。spa

對於一次詢問若是有多種方案,則採用使最終pi個桶中水的體積最小的方案。3d

示例1

輸入:4,3,[1,2,3,4],[2,2,4]code

輸出:[1,0,5]blog

說明:排序

第一次:花費一秒變爲 2 2 3 4ip

第二次:已經存在兩個水的體積同樣的桶io

第三次:花費五秒從2 2 3 4變爲4 4 4 4class

 

思路

先來看一下題幹,讓咱們求使最終pi個桶中水的體積最小的方案,也就是說每次向水較少的桶中注水,所以考慮先給n個水桶按含水體積從小到大排個序。要求使其中pi個桶中水的體積相同,對這句話的理解是在排好序的數組中連續pi個數相同。解題的總思路是:每次詢問時枚舉全部可能的狀況,找到花費最小的位置存入res[]中,肯定最佳方案後再向桶裏注水(修改桶中水的值,即修改數組值)。變量

 

下面結合例子具體來講一說一次詢問時的過程:

  • 一共有6個水桶,水桶中初始水的體積爲[9, 2, 6, 1, 8, 3],排序後的數組爲[1, 2, 3, 6, 8, 9],假設某次詢問時pi=4,min表示每次詢問時最少花費的時間,min_begin表示使花費時間最少的方案的起始水桶的位置
  • 能夠想象有一個固定大小爲4的滑動窗口,從begin=0位置開始向右滑動,sum表示pi個桶中原始水的體積,total表示注水後pi個桶中水的體積
  • 第一次:sum=a[0]+a[1]+a[2]+a[3]=12,注水後前4個桶中的水的體積都變成了a[3]=6,因此total=pi*6=24;此時min=total-sum=12,min_begin=0
  • 第二次:sum=a[1]+a[2]+a[3]+a[4]=19,注水後第2~5個桶中的水的體積都變成了a[4]=8,因此total=pi*8=32;此時total-sum=13>12,不須要更新min和min_begin
  • 第三次:sum=a[2]+a[3]+a[4]+a[5]=26,注水後第3~6個桶中的水的體積都變成了a[5]=9,因此total=pi*9=36;此時total-sum=10<12,更新min=10,min_begin=2
  • 本次詢問結束。當pi=4時最小的方案是第三次中的方案,即便a[2]到a[5]桶中的水都爲9,將min=10存入res[i]中,而後遍歷下標爲min_begin到min_begin+pi-1的區間並將該區間內的值修改成a[min_begin+pi-1]=9

Tips:

  • 計算sum時能夠利用滑動窗口的特色,去掉移出窗口的值而後加上新移進窗口的值,即sum=sum-a[begin-1]+a[begin+pi-1],其中begin爲當前方案中第一個桶的位置
  • 詢問數組p中可能會有重複的值,或是不須要再注水的值(當前n個水桶中含有相同體積水的桶的數目大於pi),這種狀況下直接跳過。能夠用一個變量equal來記錄n個桶中含有相同水的桶的個數,每一輪詢問結束後更新equal爲Math.max(equal, pi),下一次詢問前先判斷該次詢問的pi和equal的大小,若是pi<=equal,說明無需注水,另res[i]=0而後直接進入下一輪。

JAVA代碼

public class Solution {
    /**
     * 
     * @param n int整型 水桶的個數
     * @param q int整型 詢問的次數
     * @param a int整型一維數組 n個水桶中初始水的體積
     * @param p int整型一維數組 每次詢問的值
     * @return int整型一維數組
     */
    public int[] solve (int n, int q, int[] a, int[] p) {
        int[] res = new int[q];
        Arrays.sort(a);
        int equal = 0;
        for(int i = 0; i < q; i++) {
            if(p[i] <= equal) {
                res[i] = 0;
                continue;
            }
            int sum = 0;
            for(int j = 0; j < p[i]; j++) {
                sum += a[j];
            }
            int min = a[p[i] - 1] * p[i] - sum, min_begin = 0;;
            for(int begin = 1; begin <= n - p[i]; begin++) {
                sum = sum - a[begin - 1] + a[begin + p[i] - 1];
                if(a[begin + p[i] - 1] * p[i] - sum < min) {
                    min = a[begin + p[i] - 1] * p[i] - sum;
                    min_begin = begin;
                }
            }
            res[i] = min;
            equal = Math.max(equal, p[i]);
            for(int j = min_begin; j < min_begin + p[i]; j++) {
                a[j] = a[min_begin + p[i] - 1];
            }
        }
        return res;
    }
}
相關文章
相關標籤/搜索