leetcode 1167题 使用贪心的算法设计思路

题目描述

为了装修新房,你需要加工一些长度为正整数的棒材 sticks。

如果要将长度分别为 X 和 Y 的两根棒材连接在一起,你需要支付 X + Y 的费用。 由于施工需要,你必须将所有棒材连接成一根。

返回你把所有棒材 sticks 连成一根所需要的最低费用。注意你可以任意选择棒材连接的顺序。

示例 1:
输入:sticks = [2,4,3]
输出:14
解释:先将 2 和 3 连接成 5,花费 5;再将 5 和 4 连接成 9;总花费为 14。

示例 2:
输入:sticks = [1,8,3,5]
输出:30

提示:
1 <= sticks.length <= 10^4
1 <= sticks[i] <= 10^4

解题思路

  1. 首先看下提示中的数据范围,发现长度是 1 0 4 10^4 104数量级的,这样一来, O ( n 2 ) O(n^2) O(n2)的算法就是不能用了。
  2. 接下来我们考虑 O ( n l o g n ) O(nlogn) O(nlogn)的算法。
  3. 通过观察数据可知,我们希望尽量多使用长度短的,少使用长度长的。换句话说,我们希望先将短的加成长的。这样可以尽量少使用长的,来降低总的成本。
  4. 这里就可以使用贪心的算法设计思路来设计算法了。
  5. 再进一步,我们发现,这个思路和哈夫曼编码的思路很像,具体而言,他们都是让权重大的数据编码长度小一点。
  6. 所以,哈夫曼编码的思路也是可以借鉴的。
  7. 而哈夫曼编码的思路是可以优化的,具体而言,在单单求整体编码长度的时候,我们不需要将整个树构建出来,而是只需要将每次两个节点权重相加的结果加入答案即可。
  8. 仔细想来,是可以想明白的:第一次相加的时候,他们就像是在底层一样,就是使用一位就能编码,所以对答案的贡献就是总长;第二次加的时候,他们就在第二层了,需要两位才能编码,贡献就是总长的两倍,以此类推。
  9. 这道题的思路也是一样的。
class Solution {
public:
    int countSmaller(vector<int>& nums) {
        priority_queue<int, vector<int>, greater<> > Heap;
        for (int num: nums)
            Heap.push(num);
        int ans(0);
        while (Heap.size() > 1) {
            int x = Heap.top(); Heap.pop();
            int y = Heap.top(); Heap.pop();
            ans += (x + y);
            Heap.push(x + y);
        }
        return ans;
    }
}; 

补充知识点

  1. 这里面使用了优先队列 priority_queue。

  2. priorty_queue是容器适配器,第一个参数是成员类型,第二个是底层容器,就是用什么来装数据。第三个参数是比较函数,great<>则说明是小元素优先级高,less<>相反

  3. priority_queue是一个容器适配器,即把某个底层容器包装起来,好去模拟某种有新功能的数据结构。但这样也就丧失了底层容器的迭代器功能。priority_queue类模板需要提供三个参数:一个成员类型T,一个底层容器类型Container ,和一个比较函数Comp。底层容器默认用vector,而比较函数默认用std::less函数,越大的优先级越高。

  4. 例子priority_queue< int , vector , greater > que;意思是,这个priority_queue里的数据类型是int,它是用vector作为底层容器实现,并且用系统提供的greater函数作为比较标准。于是越小的数优先级越高。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值