当青训营遇上码上掘金--主题 4:攒青豆

71 阅读3分钟

当青训营遇上码上掘金--主题 4:攒青豆

先把题目扒过来,好看一点

  • 主题 4:攒青豆

    现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

攒青豆.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

贪心算法思路

看到这道题目的时候,我选择了一个贪心的算法

先找到最高的两个柱子,先算最高的两个柱子之间能得到多少豆子,若这两个柱子是最边上的,那就直接打印总数并结束;若不在边上,那就找下一个高的柱子和刚刚的第二高的柱子所得到的豆子

也就是说,我会先将所有柱子按高到低排列并存入结构体的数组里,结构体的x值为数组索引,y值为高度。然后从高到低循环计算每两个柱子之间的豆子。

为什么贪心

若高柱子离得越远,循环次数就越少

若再优化一下,增加一点条件判断语句,甚至可以不用再计算已经计算过的豆子

如何结束循环

采用计数方法,新创建一个对应索引值的数组key,每当遍历到一个高度y值后,其索引在key中的值更改为-1,直到最后key中所有值为-1即可结束循环

待优化:可以用切片,每当遍历到一个高度y值后,在key中删除这个值,直到key为空时结束循环

解决重复计算豆子的问题

按照这种贪心算法,会存在重复计算豆子的问题,如:[3,0,5,0,4,1],会先计算5-4之间的豆子,然后计算4-3之间的豆子,可是5-4是被4-3所包含的,所以会存在多次计算同一地方的豆子

解决方案:给予计算豆子一个条件,例如4-3,若4-3中间出现比3大的柱子就跳过。但是5-4之间的0还是会被重复计算呢,那该怎么办呢,那就在计算完5-4之间的豆子之后以及计算4-3之前,把已经计算过的豆子改为5-4之间较小的值,即为4。同理计算完4-3后,改变其中间的柱子高度为3。这样就完美解决问题了。

代码

code.juejin.cn/pen/7195485…

package main

import (
   "fmt"
   "sort"
)

func main() {

   m := make(map[int]int)
   height := []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
   key := make([]int, len(height))
   for i := 0; i < len(height); i++ {
      m[i] = height[i] //将数组的索引和值对应为map
      key[i] = i       //key是索引值,x值
   }
   
   type position struct {
      x int
      y int       //x对应索引,y对应高度
   }
   
   var lstposition []position

   for x, y := range m {
      lstposition = append(lstposition, position{x, y})
   }

   sort.Slice(lstposition, func(i, j int) bool {
      return lstposition[i].y > lstposition[j].y // 降序
   })

   //以上为结构体数组按柱子高度降序的排序

 
   sum := 0
   
   //以下为计数以及计算总值的代码
       
   for i := 0; ; i++ {
      if lstposition[i].x < lstposition[i+1].x {
         for j := lstposition[i].x; j <= lstposition[i+1].x; j++ {
            if j == lstposition[i].x || j == lstposition[i+1].x {

            } else {
               if lstposition[i+1].y > height[j] {
                  sum += lstposition[i+1].y - height[j]
                  height[j] = lstposition[i+1].y
               }
            }
            key[j] = -1
         }
      } else {
         for j := lstposition[i+1].x; j <= lstposition[i].x; j++ {
            if j == lstposition[i].x || j == lstposition[i+1].x {

            } else {
               if lstposition[i+1].y > height[j] {
                  sum += lstposition[i+1].y - height[j]
                  height[j] = lstposition[i+1].y
               }
            }
            key[j] = -1
         }

         //以下为结束循环的条件
         count := 0
         for j := 0; j < len(key); j++ {
            if key[j] == -1 {
               count++
            }
         }

         if count == len(key) {
            //fmt.Println("count:", count)
            fmt.Println(sum)
            break
         }

      }

   }

}