题目:一样的水
描述:有n个水桶,第i个水桶里面水的体积为Ai,你可以用1秒时间向一个桶里添加1体积的水。有q次询问,每次询问一个整数pi,你需要求出使其中pi个桶中水的体积相同所花费的最少时间。对于一次询问如果有多种方案,则采用使最终pi个桶中水的体积最小的方案。
示例1:输入:4,3,[1,2,3,4],[2,2,4],返回值:[1,0,5]
说明:第一次:花费一秒变为 2 2 3 4
第二次:已经存在两个水的体积一样的桶
第三次:花费五秒从2 2 3 4变为4 4 4 4
解法一:
思路分析:首先我们分析题目的含义,题目中输入一共包含4个字符,n表示有n个桶,q表示有q次询问,容器a表示n个水桶中初始水的体积,容器p表示需要询问多少次以及询问的值,题目的意思也很明确,就是每询问一次,你需要保证使pi个桶中水的体积相同所花费的最少时间,因为每次1秒钟内只能添加1体积的水。
——我们以示例1为例进行上述分析:
——通过对示例1的解析,我们明白了题目的含义,在编写程序的过程中,我们应该首先设定一个存储对象res和对数组a进行升序排序,因为升序排序之后我们可以缩短运行的时间,题目中只要求两个桶的水体积相同,没有要求具体的哪两个桶,其次我们需要遍历询问的对象,因为我们需要通过询问的对象来确定需要几个桶的水的体积相同,所以我们在此需要设定一个指针对象i(i的值为询问数组的首值),我们可以通过i来首先确定一个量,即sum_min,sum_min的值等于第i个值的量乘以i就是有i个桶的水的体积的总量,然后减去前i个数的总和,就可以得到一个初始化的量,随后只需要循环a数组中连续的i个变量进行比对,就能得到一个sum_min的值,通过将数组保存好以后,再开始第二轮循环即可完成所有的值。
实例分析:
Python核心代码:
# # 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 # # # @param n int整型 水桶的个数 # @param q int整型 询问的次数 # @param a int整型一维数组 n个水桶中初始水的体积 # @param p int整型一维数组 每次询问的值 # @return int整型一维数组 # class Solution: def solve(self , n , q , a , p ): # write code here a.sort()#首先对a进行排序 res = []#设置存储对象 for i in p:#遍历询问对象 start = 0 sum_i = sum(a[:i])#前i项的和 dif = sum_i sum_min = a[i - 1]*i - sum_i #计算得到前方的最小值,就是用该值的大小乘以i减去前面的i项和 for j in range(i,n): dif += a[j] - a[j - i] if a[j] * i - dif < sum_min:#验证 start = j + 1 - i sum_min = a[j] * i - dif a[start:start + i] = [a[start + i - 1]] * i#保存 res.append(sum_min)#添加进结果中 return res
——因为我们首先循环的是询问对象组,所以假设询问对象组有N个元素,所以需要遍历N次,因为初始化,不能保证得到的是最小的元素,所以还需要遍历其余连续的i个元素,所以其总的时间复杂度为。因为需要额外的res存储询问返回值的对象,但是结果数组不计入空间复杂度,所以其空间复杂度为
。
解法二:
思路分析:上述分析,我们清楚的明白了该题目的意思,下面我们还可以首先将原先a数组中的元素做个累加,将累加和返回,然后再根据上述循环进行操作,首先设定一个存储容器的对象res和上述相同,再定义一个sum的值,用来存储和,再根据for循环进行最小值的计算,根据就能得到初始的最小值,和解法一的公式大致相同,最终一直更新位置,然后返回res结果值即可。
C++核心代码:
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param n int整型 水桶的个数 * @param q int整型 询问的次数 * @param a int整型vector n个水桶中初始水的体积 * @param p int整型vector 每次询问的值 * @return int整型vector */ vector<int> solve(int n, int q, vector<int>& a, vector<int>& p) { // write code here int len = a.size();//首先定义a数组的长度 sort(a.begin(), a.end());//排序 int sum[10005];//存储前n项和 sum[0] = 0; vector<int> res; for(auto i: p){//以询问为循环对象 int tmp = INT_MAX; for(int j = 1; j <= len; j++){//计算累加值 sum[j] = sum[j-1] + a[j-1]; } int sum_min = 0, ans = INT_MAX, pos; for(int j = i; j <= n; j++){//循环判断最小量 sum_min = a[j - 1] * i - (sum[j] - sum[j - i]);//计算最小值 if(sum_min < ans){ ans = sum_min;//替换 pos = j; } } for(int j = pos - 1; j >= pos - i; j--){//将位置进行更新,开始进行新的一轮 a[j] = a[pos - 1]; } res.push_back(ans); } return res; } };
——该方法相比于解法一增加了循环的量,需要将数组a的值进行累加,所以时间复杂度为,因为sum数组为存储量固定的数组,所以空间复杂度为
。