前端重拾算法数据结构一个月(8)

129 阅读1分钟

第八天

今天继续来写搜索与回溯算法的题目。

二十题

剑指 Offer 13. 机器人的运动范围

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例:

输入: m = 2, n = 3, k = 1
输出: 3

提示:

  • 1 <= n,m <= 100

  • 0 <= k <= 20

思路: 如下图所示:

image.png 在题目中有一个需要注意的点,不能进入行坐标和列坐标的数位之和大于k的格子。例如k为18的时候,不能进入(35,37)是因为3+5+3+7=18,是位数之和不是坐标之和,不是35+37。所以我先写了一个函数来进行这一步判断:

function addNum(num:number):number{
    if (num === 100) return 1   //提示中说了m和n最大为100
    return (num % 10) + (num - (num % 10)) / 10

那么我一开始异想天开地以为只需要遍历m和n让他们不断执行这个函数,能通过的就可以满足题目条件写了这么一段:

function movingCount(m: number, n: number, k: number): number {
    let canGoNum = 0

    function addNum(num:number):number{
    if (num === 100) return 1
    return (num % 10) + (num - (num % 10)) / 10
}

    for (let i = 0; i < m; i++) {
      for (let j = 0; j < n; j++) {
        if (addNum(i) + addNum(j) <= k) {
          canGoNum++
        }
      }
    }
    return canGoNum
};

结果碰壁了,我这样写应该相当于一行一行遍历,在每一行中如果遇到符合条件的就让canGoNum加一。但是失败了,结果比我算出来的要小,那么我就理解了是因为有一些点它满足,但是那些点之前有一些点是不满足的也就是无法到达的,机器人不能进行跳跃,所以即便后面的点能够满足,机器人也无法走到。所以还是得真正地让它“走”起来。

function movingCount(m: number, n: number, k: number): number {
    function addNum(num:number):number{
    if (num === 100) return 1
    return (num % 10) + (num - (num % 10)) / 10
    }

    if (k === 0) return 1
    const columnArr: number[] = new Array(n).fill(0)
    const mapArr: number[] = new Array(m).fill(columnArr)
    let sum = 0
    let goOut = false
    for (let i = 0; i < m; i++) {
      if (goOut) break
      for (let j = 0; j < n; j++) {
        if (addNum(i) + addNum(j) <= k) {
          mapArr[i][j] = 1
          console.log({ i, j })
          sum++
        } else {
          if (j === 0) {
            goOut = true
          }
          break
        }
      }
    }
    return sum
};

本以为这样可以解决,结果结果原来他在特殊的地方时会有连接的,于是只能去看了解析。

image.png 虽然写了很久还是失败了,很心累,但是还是要把它写出来!所以决定用深度优先算法去写:

function movingCount(m: number, n: number, k: number): number {
    function addNum(num:number):number{
    if (num === 100) return 1
    return (num % 10) + (num - (num % 10)) / 10
    }

    if (k === 0) return 1
    const alreadyGo = [{one:0,two:0}]
    let sum = 1

    const dfs = (line:number,column:number)=>{
            const filterArr = []
            if(line+1<m){
                if(addNum(line+1)+addNum(column)<=k){
                    filterArr.push({one:line+1,two:column})
                }
            }
            if(column+1<n){
                if(addNum(line)+addNum(column+1)<=k){
                    filterArr.push({one:line,two:column+1})
                }
            }
            if(line-1>=0){
                if(addNum(line-1)+addNum(column)<=k){
                    filterArr.push({one:line-1,two:column})
                }
            }
            if(column-1>=0){
                if(addNum(line)+addNum(column-1)<=k){
                    filterArr.push({one:line,two:column-1})
                }
            }
            console.log({filterArr});
            filterArr.forEach((item)=>{
                if(!alreadyGo.includes(item)){
                    alreadyGo.push(item)
                    sum++
                    dfs(item.one,item.two)
                }
            })
        }
        dfs(0,0)
        return sum
};

写着发现不太对劲。这题写了太多天,明天复习深度优先和广度优先的基础题型。