当青训营遇上码上掘金

48 阅读2分钟

当青训营遇上码上掘金

题目描述

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。

步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)

思路

BFS,从小青在的地点,开始搜索小青可以到达的所有节点,直到找到小码。

小青所在点是N,从N节点开始进行广搜,把可达未入队地点入队,然后拿队头节点搜(有三个,分别是+1 -1 *2)如果能更新结果dist数组就更新,不能更新就出队,继续一层一层的找下去。dist 记录答案,dist[i] 代表从节点N 到达节点i 所需的最短时间。 如果已经找到了小青,那么就直接返回dist【i】就可以了。

广搜的结果就是最短路径。

代码实现

go菜鸡想找实现好的队列,但是很遗憾没找到。go好像没有实现好的队列,所以自己手写了一个队列。

package main

import (
   "fmt"
)

type Queue struct {
   List []int
}

// 创建一个新队列
func newQueue() *Queue {
   list := make([]int, 0)
   return &Queue{List: list}
}

// 入队一个数据
func (q *Queue) inQ(data int) {
   q.List = append(q.List, data)
}

// 出队一个数据
func (q *Queue) popQ() int {
   if len(q.List) == 0 {
      return -1
   }

   data := q.List[0]
   q.List = append(q.List[1:])
   return data
}

// 判断队列是否为空
func (q *Queue) empty() bool {
   if len(q.List) == 0 {
      return true
   }
   return false
}

func bfs(n int, k int) int {
   //小青和小码在同一个位置
   if n == k {
      return 0
   }
   //结果数组,存结果
   var dist [100000]int
   for count := 0; count < len(dist); count++ {
      dist[count] = 100005
   }
   //是否访问过数组,防止重复入队
   var vis [100000]bool
   //队列
   queue := newQueue()
   //小青位置n入队了
   queue.inQ(n)
   dist[n] = 0
   vis[n] = true

   for !queue.empty() {
      currentNode := queue.popQ()

      //找到小青所在地k了
      if currentNode-1 == k || currentNode+1 == k || currentNode*2 == k {
         return dist[currentNode] + 1
      }
      // 步行向后走一步
      if currentNode > 0 && dist[currentNode-1] > dist[currentNode]+1 {
         dist[currentNode-1] = dist[currentNode] + 1
         if !vis[currentNode-1] {
            queue.inQ(currentNode - 1)
            vis[currentNode-1] = true
         }
      }
      // 步行向前走一步
      if currentNode < 100000 && dist[currentNode+1] > dist[currentNode]+1 {
         dist[currentNode+1] = dist[currentNode] + 1
         if !vis[currentNode+1] {
            queue.inQ(currentNode + 1)
            vis[currentNode+1] = true
         }
      }
      // 公交
      if 2*currentNode <= 100000 && dist[2*currentNode] > dist[currentNode]+1 {
         dist[2*currentNode] = dist[currentNode] + 1
         if !vis[2*currentNode] {
            queue.inQ(2 * currentNode)
            vis[2*currentNode] = true
         }
      }
   }
   return -1
}

func main() {
   fmt.Println(bfs(2, 4096))
}

image.png