题意:
计算n个数的和,已知计算x,y两个数的和,需要花费(c*x+c*y)秒。
输出计算n个数字和的最小花费的时间。
方法一:
最小堆
思路:根据贪心思想,每次取出两个最小的数相加,并将两个最小的数之和push进队列。
利用小根堆(优先队列),因为小根堆每次取出的都是最小值。
typedef long long ll;
class Solution {
public:
long long solve(int n, int c, vector<int>& a) {
priority_queue<int,vector<int>,greater<int>> q;//小根堆
for(int i=0;i<n;i++){
q.push(a[i]);
}
ll sum=0;
while(q.size()>1){//当队列的大小>1时
int x=q.top();//每次取出两个最小的数相加
q.pop();
int y=q.top();
q.pop();
q.push(x+y);//向队列push两个最小的数之和
sum+=x+y;
}
return sum*c;
}
};
时间复杂度:
空间复杂度:![]()
方法二:
map查找
思路:map是红黑树实现,值是有序的(从小到大)。用map记录值为a[i]出现的次数。每次取出两个最小的数相加(即前两个数)相加。
typedef long long ll;
class Solution {
public:
long long solve(int n, int c, vector<int>& a) {
map<int,int> m;//有序红黑树
for(int i=0;i<n;i++)//初始化,记录值为a[i]出现的次数
m[a[i]]++;
ll sum=0;
for(int i=0;i<n-1;i++){
int x=m.begin()->first,y;//寻找两个最小的数
if(--m[x]==0){//如果m[x]==0,说明该值用完,删除掉该键
m.erase(m.begin());
y=m.begin()->first;
if(--m[y]==0)
m.erase(m.begin());
}else{
y=x;
if(--m[x]==0)//如果m[x]==0,说明该值用完,删除掉该键
m.erase(m.begin());
}
sum+=x+y;
m[x+y]++;
}
return sum*c;
}
};
时间复杂度:
空间复杂度:![]()



京公网安备 11010502036488号