860.柠檬水找零
所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。
func lemonadeChange(bills []int) bool {
cash:=[2]int{}
for _,n:=range bills{
if n==5{
cash[0]++
}else if n==10{
cash[0]--
cash[1]++
}else{
if cash[1]>0{
cash[1]--
cash[0]--
}else{
cash[0]-=3
}
}
if cash[0]<0{
return false
}
}
return true
}
406.根据身高重建队列
两个贪心
1.局部最优身高从高到低并且同身高符合要求
2.局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性
全局最优:最后都做完插入操作,整个队列满足题目队列属性
func reconstructQueue(people [][]int) [][]int {
sort.Slice(people, func(i, j int) bool {
if people[i][0] == people[j][0] {
return people[i][1] < people[j][1]
}
return people[i][0] > people[j][0]
})
res :=[][]int{}
for _,n:=range people{
if len(res)==0{
res=append(res,n)
continue
}
count:=n[1]
for i2,n2:=range res{
if n2[0]>=n[0]{
count--
}
if count<0{
res=append(res,[]int{})
copy(res[i2+1:],res[i2:])
res[i2]=n
break
}
if count==0{
if i2==len(res){
res=append(res,n)
}else{
res=append(res,[]int{})
copy(res[i2+2:],res[i2+1:])
res[i2+1]=n
}
break
}
}
}
return res
}
优化插入
func reconstructQueue(people [][]int) [][]int {
// 先将身高从大到小排序,确定最大个子的相对位置
sort.Slice(people, func(i, j int) bool {
if people[i][0] == people[j][0] {
return people[i][1] < people[j][1] // 当身高相同时,将K按照从小到大排序
}
return people[i][0] > people[j][0] // 身高按照由大到小的顺序来排
})
// 再按照K进行插入排序,优先插入K小的
for i, p := range people {
copy(people[p[1]+1 : i+1], people[p[1] : i+1]) // 空出一个位置
people[p[1]] = p
}
return people
}
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后再按照另一个维度重新排列。
其实如果大家认真做了135. 分发糖果 (opens new window),就会发现和此题有点点的像。
在135. 分发糖果 (opens new window)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。
如果两个维度一起考虑一定会顾此失彼。
对于本题相信大家困惑的点是先确定k还是先确定h呢,也就是究竟先按h排序呢,还是先按照k排序呢?
如果按照k来从小到大排序,排完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
那么按照身高h来排序呢,身高一定是从大到小排(身高相同的话则k小的站前面),让高个子在前面。
此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!
那么只需要按照k为下标重新插入队列就可以了。
452.用最少数量的箭引爆气球
注意先对气球排序
局部最优,只从重叠部分射
func findMinArrowShots(points [][]int) int {
cross:=[][]int{}
sort.Slice(points, func (i,j int) bool {
return points[i][0] < points[j][0]
})
for _,ballon:=range points{
if len(cross)==0{
cross=append(cross,ballon)
}
notcross:=true
for _,xy:=range cross{
if ballon[0]<=xy[1]&&ballon[1]>=xy[0]{
xy[1]=min(ballon[1],xy[1])
xy[0]=max(ballon[0],xy[0])
notcross=false
}
}
if notcross{
cross=append(cross,ballon)
}
}
return len(cross)
}
func min(i,j int) int{
if i<j{
return i
}
return j
}
func max(i,j int) int{
if i>j{
return i
}
return j
}
直觉上来看,貌似只射重叠最多的气球,用的弓箭一定最少,那么有没有当前重叠了三个气球,我射两个,留下一个和后面的一起射这样弓箭用的更少的情况呢?
尝试一下举反例,发现没有这种情况。
那么就试一试贪心吧!局部最优:当气球出现重叠,一起射,所用弓箭最少。全局最优:把所有气球射爆所用弓箭最少。
func findMinArrowShots(points [][]int) int {
var res int = 1 //弓箭数
//先按照第一位排序
sort.Slice(points, func (i,j int) bool {
return points[i][0] < points[j][0]
})
for i := 1; i < len(points); i++ {
if points[i-1][1] < points[i][0] { //如果前一位的右边界小于后一位的左边界,则一定不重合
res++
} else {
points[i][1] = min(points[i - 1][1], points[i][1]); // 更新重叠气球最小右边界,覆盖该位置的值,留到下一步使用
}
}
return res
}
func min(a, b int) int {
if a > b {
return b
}
return a
}
模拟射气球过程
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后再按照另一个维度重新排列。
其实如果大家认真做了135. 分发糖果 (opens new window),就会发现和此题有点点的像。
在135. 分发糖果 (opens new window)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。
如果两个维度一起考虑一定会顾此失彼。
对于本题相信大家困惑的点是先确定k还是先确定h呢,也就是究竟先按h排序呢,还是先按照k排序呢?
如果按照k来从小到大排序,排完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。
那么按照身高h来排序呢,身高一定是从大到小排(身高相同的话则k小的站前面),让高个子在前面。
此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!