题解 | #一样的水#

一样的水

http://www.nowcoder.com/practice/c880afeeaeeb4316b19e784452216e23

题目:一样的水
描述:有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数组为存储量固定的数组,所以空间复杂度为

算法自然分析 文章被收录于专栏

在解决问题的同时,不断与人交流学习,通过牛客各式各样的题目,学习分享。

全部评论

相关推荐

点赞 1 评论
分享
牛客网
牛客企业服务