【每日一题】2208 . 将数组和减半的最少操作

【每日一题】2208 . 将数组和减半的最少操作

2208 . 将数组和减半的最少操作

题目描述

给你一个正整数阵列 nums 。每次操作中,你 nums 可以选择任意 一个数并将其减少到大约 一半。(注意,在后续操作中你可以对减少半过的数继续执行操作)

请您返回nums 数据库并至少 减少一半的最少 操作数。

示例1:

输入: nums = [5,19,8,1]
输出: 3
解释:最终 nums 的和为 5 + 19 + 8 + 1 = 33 。
以下是减少存储量至少一半的一种方法:
选择数字 19 并减少为 9.5 。
选择 Digital 9.5 并减少为 4.75 。
选择数字 8 并减少为 4 。
最终吞吐量为 [5, 4.75, 4, 1] ,和为 5 + 4.75 + 4 + 1 = 14.75 。
nums 的和减少了 33 - 14.75 = 18.25 ,减少的部分超过了最终备份和一半,18.25 >= 33/2 = 16.5 。
我们需要 3 个操作实现题目,所以返回 3 。
可以证明,无法通过减少 3 个操作使存储量减少至少一半。

示例2:

输入: nums = [3,8,20]
输出: 3
解释:最终 nums 的和为 3 + 8 + 20 = 31 。
以下是减少存储量至少一半的一种方法:
选择数字 20 并减少为 10 。
选择数字 10 并减少为 5 。
选择数字 3 并减少为 1.5 。
最终吞吐量为 [1.5, 8, 5] ,和为 1.5 + 8 + 5 = 14.5 。
nums 的和减少了 31 - 14.5 = 16.5 ,减少的部分超过了最终吞吐量和一半, 16.5 >= 31/2 = 16.5 。
我们需要 3 个操作实现题目,所以返回 3 。
可以证明,无法通过减少 3 个操作使存储量减少至少一半。

提示:

1 <= nums.length <= 105
1 <= nums[i] <= 107

解题思路

思路:贪心+大根堆(优先队列)。要求将数组和至少减半的最少操作次数,那么可以每次将数组中的最大值拿出来减半,故可以维护一个大根堆,然后每次取出堆顶减半再插回去,直至至少减半。

class Solution {
public:
    int halveArray(vector<int>& nums) {
        priority_queue<double> pq(nums.begin(),nums.end());
        double sum=accumulate(nums.begin(),nums.end(),0.0);
        int count=0;
        double target=0;
        while(target<sum/2)
        {
            double top=pq.top();
            double num=top/2;
            target+=num;
            pq.pop();
            pq.push(num);
            count++;
        }
        return count;
    }
};

总结:注意一些细节。使用priority_queue<double> pq(nums.begin(),nums.end())初始化大根堆,注意是double类型的喔;使用sum=accumulate(nums.begin(),nums.end(),0.0)来累计数组和,这样可以不用for循环求和的喔;pri_que.push()向队列中添加一个元素;pri_que.pop()将队列中优先级最高的元素删除;pri_que.top()获取队列中优先级最高的元素;pri_que.size()获取队列的大小;pri_que.empty()判断队列是否为空;priority_queue<typename, container, functional> pri_que初始化优先级队列,其中typename表示数据的类型,container表示容器的类型,默认是vector容器,functional表示比较的方式,默认是大顶堆less<type>,如果是小顶堆则是greater<type>,当数据类型不是基本数据类型而是自定义数据类型时,就不能使用greater或者less比较方式了,而是需要自定义比较方式,注意,其中堆的cmp与sort的cmp相反的,即堆的>表示小根堆,堆的<表示大根堆。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于分治思想的求解n元素数组中最大元素的位置的算法的伪代码: ``` def find_max_index(array, start, end): if start == end: return start else: mid = (start + end) // 2 left_max_index = find_max_index(array, start, mid) right_max_index = find_max_index(array, mid+1, end) if array[left_max_index] >= array[right_max_index]: return left_max_index else: return right_max_index ``` 该算法的基本思想是将数组分成两个部分,分别递归求解每个子数组的最大元素,然后将两个子数组的最大元素进行比较,返回较大者的下标作为整个数组的最大元素的下标。 对于问题1,如果数组中的若干个元素都具有最大值,该算法的输出是不确定的,因为在比较过程中可能会选择其中一个最大值,而不是所有最大值。 对于问题2,建立该算法的键值比较次数的递推关系式如下: - 当n=1时,比较次数为0。 - 当n>1时,假设左右子数组的长度分别为n1和n2,则总比较次数为T(n) = T(n1) + T(n2) + 1。因为每次比较都可以将问题规模减半,所以n1和n2的最大值为n/2,因此有n1 + n2 = n,代入上式得到T(n) = T(n/2) + T(n/2) + 1 = 2T(n/2) + 1。 根据主定理,可以得到该算法的时间复杂度为O(nlogn)。 对于问题3,该分治算法的比较次数较蛮力算法要少,因为每次将问题规模减半,因此总比较次数为O(nlogn),而蛮力算法的总比较次数为O(n)。但是,该分治算法需要递归调用函数,因此需要额外的空间来存储每个递归调用的返回值,空间复杂度为O(logn),而蛮力算法的空间复杂度为O(1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值