前言
本博客会分享Leetcode3218. 切蛋糕的最小总开销 I解题思路,这是12月25日的每日一题。文章第二部分会分享一下自己的解题思维过程,如何通过刷题提升自己的算法能力。
3218. 切蛋糕的最小总开销 I - 力扣(LeetCode)
看完题目的第一反应,这道题应该是用贪心算法进行解题。可以想到满足最终答案res
有以下公式:
r
e
s
=
∑
C
u
t
∗
(
C
o
t
O
p
p
o
s
i
t
e
S
i
d
e
+
1
)
res=\sum{Cut}*(CotOppositeSide+1)
res=∑Cut∗(CotOppositeSide+1)
Cut
指切蛋糕的花销,CotOppositeSide
指异侧已经切了的刀数。根据样例中的动图:
- 第一刀,沿垂直线0切时:
Cut
=5,CotOppositeSide
=0 - 第二刀,沿水平线0切时:
Cut
=1,CotOppositeSide
=1 - 以此类推…
对于某一刀花销Cut
是一定的,所以CotOppositeSide
与res
是正相关。要想使答案尽可能的小,就得尽量让较大的Cut
对应较小的CotOppositeSide
。结合题目中给的数据范围,一开始我想到用堆维护当前Cut
的最大值,并且需要回溯去分别计算水平最大值优先或者垂直最大值优先的结果,最后再输出最小值。但是实际上并不需要,直接同时考虑全局下的花销最大值即可,也就有了如下的代码:
int minimumCost(int m, int n, vector<int>& horizontalCut, vector<int>& verticalCut) {
priority_queue<pair<int,bool>,vector<pair<int,bool>>,less<>> q;
for(int i=0;i<horizontalCut.size();i++){
q.push({horizontalCut[i],true});
}
for(int i=0;i<verticalCut.size();i++){
q.push({verticalCut[i],false});
}
int hori=0,vert=0;
int res=0;
while(!q.empty()){
auto tmp=q.top();
q.pop();
if(tmp.second){
res+=tmp.first*(vert+1);
hori++;
}
else{
res+=tmp.first*(hori+1);
vert++;
}
}
return res;
}
这段代码能过这道题,甚至困难难度的3219. 切蛋糕的最小总开销 II - 力扣(LeetCode)也能勉强过。代码时间复杂度为O(mlogm+nlogn+(n+m)log(m+n)),仍有优化的空间
学习题解
优化自己的代码
如果只是单纯的维护Cut
的最大值,没有必要使用堆去维护,每次出堆都会需要再次调整堆,导致了不必要的时间开销。只需要对数组进行排序,然后再用双指针控制此时Cut
是最大值即可,这样处理之后算法的时间复杂度降低到了O(mlogm+nlogn).优化后得到了如下的代码:
int minimumCost(int m, int n, vector<int>& horizontalCut, vector<int>& verticalCut) {
sort(horizontalCut.begin(),horizontalCut.end(),greater());
sort(verticalCut.begin(),verticalCut.end(),greater());
int hor=0,ver=0;
auto it_hor=horizontalCut.begin(),it_ver=verticalCut.begin();
int res=0;
while(it_hor!=horizontalCut.end() || it_ver!=verticalCut.end()){
//注意处理指针已经到数组最后的情况
if(it_hor!=horizontalCut.end() && it_ver!=verticalCut.end()){
if(*it_hor>(*it_ver)){
res+=(*it_hor)*(ver+1);
it_hor++;
hor++;
}
else{
res+=(*it_ver)*(hor+1);
it_ver++;
ver++;
}
}
else if(it_hor!=horizontalCut.end()){
res+=(*it_hor)*(ver+1);
it_hor++;
}
else{
res+=(*it_ver)*(hor+1);
it_ver++;
}
}
return res;
}
学习新算法
在看题解的时候,关注都灵神的题解,用的是最小生成树的 Kruskal 算法。自然而然就会驱使自己去学习这个此前没有学习过的算法,加之有这道题的背景,学习新算法的时候就更容易理解新算法的思想,能更快掌握新的算法。至此,总结出如下的刷算法题的思维导图:
谢谢你的阅读!