二叉树、深度优先、广度优先、回溯

46. 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]

解:
1.对与DFS的题 画出下面这个图
在这里插入图片描述
2.设答案数组为ans ans中包含的一个个数组用arr标志
3.左边这个黑框第一列代表标志数组 用来记录这个数是否在arr中 第二列代表需要进行全排列的数组 本题解是[5,6,7] 本题是[1,2,3] 第三列代表当前遍历到哪一层 当层数=数组长度时 将arr加入ans中
4.由于本题数字不能重复使用 即不能出现[5,5,5] 这种数组 所以我们需要一个标志数组来记录 哪些数字加入了arr
5.DFS代码套路:
(1)先确定回溯条件:当层数=数组长度时 相当于遍历完了 完成了一次全排列 将arr加入ans中
(2)DFS代码:因为要全排列 所以第一步肯定是遍历数组 判断该数字是否已经在arr中 若不在 则加入 更改标志位 进入下一层 调用DFS
(3)执行完dfs(nums, flags, index, ans, arr);这行代码代表你已经完成一次全排列了 现在需要回溯:将刚才设置的标志位全部复原:从arr中弹出元素 复原标志位 改变层数
6.注意将arr添加到ans时 需要拷贝当前的arr添加到ans:arr.slice() 因为你后面还要对arr进行操作 比如回溯时会移除最后一个元素 那么ans中的arr也会跟着变 所以这里一定要记得拷贝!
代码如下:
JS:

var permute = function(nums) {
    let flags = [];
    for (let i = 0; i < nums.length; i++) {
        flags.push(false);
    }
    let ans = [];
    let arr = [];
    dfs(nums, flags, 0, ans, arr);
    return ans;
};
function dfs(nums, flags, index, ans, arr) {
    if (index === nums.length) {
        ans.push(arr.slice());
        return;
    }
    for (let i = 0; i < nums.length; i++) {
        if (!flags[i]) {
            arr.push(nums[i]);
            flags[i] = true;
            index++;
            dfs(nums, flags, index, ans, arr);
            arr.pop();
            flags[i] = false;
            index--;
        }
    }
}

也可以用set代替flags 代码如下:但是不建议这样做 因为在数据较少情况下 用数组比用set好

var permute = function(nums) {
        let flags = new Set();
        let ans = [];
    let arr = [];
    dfs(nums, flags, 0, ans, arr);
    return ans;
};
function dfs(nums, flags, index, ans, arr) {
    if (index === nums.length) {
        ans.push(arr.slice());
        return;
    }
    for (let i = 0; i < nums.length; i++) {
        if (!flags.has(i)) {
            arr.push(nums[i]);
            flags.add(i);
            index++;
            dfs(nums, flags, index, ans, arr);
            arr.pop();
            flags.delete(i);
            index--;
        }
    }
}

JAVA:

public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> lists = new LinkedList<>();
        List<Integer> list = new LinkedList<>();
        boolean[] used = new boolean[nums.length];
        dfs(nums,0,lists,list,used);
        return lists;
    }

    private static void dfs(int[] nums,int i,List<List<Integer>> lists,List<Integer> list,boolean[] used){
        if (i == nums.length) {
            lists.add(new LinkedList<>(list));
            return;
        }
        for (int j = 0; j < nums.length; j++) {
            int num = nums[j];
            if (!used[j]){
                used[j] = true;
                list.add(num);
                dfs(nums,i + 1,lists,list,used);
                used[j] = false;
                list.remove(list.size() - 1);
            }
        }
    }

剑指 Offer 38. 字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
解:

有三种提取部分字符串的方法:

  1. slice(start, end):提取某个字符串的一部分[start,end),并返回一个新的字符串,且不会改动原字符串。
    语法:str.slice(beginIndex[, endIndex])
    参数:
    (1)beginIndex:从该索引(以 0 为基数)处开始提取原字符串中的字符。如果值为负数,会被当做 strLength + beginIndex 看待,这里的strLength 是字符串的长度,也就是说负数代表倒数
    (2)endIndex:可选。在该索引(以 0 为基数)处结束提取字符串。如果省略该参数,slice() 会一直提取到字符串末尾。如果该参数为负数,则被看作是 strLength + endIndex,这里的 strLength 就是字符串的长度
  2. substring(start, end):返回一个字符串在开始索引到结束索引之间[start,end)的一个子集。
    语法:str.substring(indexStart[, indexEnd])
    参数:
    (1)indexStart:必须。从该索引(以 0 为基数)处开始提取原字符串中的字符。
    (2)indexEnd:可选。在该索引(以 0 为基数)处结束提取字符串。如果省略该参数,substring() 会一直提取到字符串末尾。
    注意:
    (1)如果任一参数小于 0 或为 NaN,则被当作 0。
    (2)如果任一参数大于 stringName.length,则被当作 stringName.length。
    (3)如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。
  3. substr(start, length):返回一个字符串中从指定位置开始到指定字符数的字符。可能会被移除 substring用来代替他

代码如下:
JS:

var permutation = function(s) {
    let set = new Set();
    let ans = [];
    let used = [];
    used.fill(false);
    let string = '';
    bfs(0);
    function bfs (i) {
        if (i === s.length) {
            set.add(string.slice());
            return;
        }
        for (let j = 0; j < s.length; j++) {
            if (!used[j]){
                used[j] = true;
                string += s.charAt(j);
                bfs(i + 1);
                used[j] = false;
                string = string.substring(0, string.length - 1);
            }
        }
    }
    set.forEach(v => {
        ans.push(v);
    })
    return ans;
};

79. 单词搜索

剑指 Offer 12. 矩阵中的路径

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例1:
这里是引用
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2:
在这里插入图片描述
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “SEE”
输出:true
示例 3:
在这里插入图片描述
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB”
输出:false

解:
1.遍历数组board 找到board中和word.charAt(index)相等的字符 以该字符为中心向四周扩散 扩散时 只要上下左右四个方向有一个返回true则代表结果为true 若全是false不能说明结果是false 因为board数组中可能有重复元素 可能board中下一个和word.charAt(index)相等的字符会返回true 所以一定要遍历完board数组
2.边界条件:索引越界 该方向的字符和word中的字符不相等
3.只有当word中的字符全都找到了才返回true
4.由于【同一个单元格内的字母不允许被重复使用】 所以扩散时用到的每一个board中的元素都要记录 以前我会定义一个布尔数组来记录 但是现在我发现 只要让他们等于" " 就行了 不用再定义变量!
5.扩散时 调用dfs(i+1, j,index+1)时一定不能写i++ 或i-- 因为i+1原来的i不变 剪枝回来之后i还是原来的i i++原来的i变了 剪枝回来后i已经变了

var exist = (board, word) => {
    if ((board.length * board[0].length) < word.length) return false;
    // let used = Array.from(new Array(board.length),() => new Array(board[0].length).fill(false));
    var dfs = function (i, j, index) {// i行 j列 index时word的索引
        if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] !== word.charAt(index)) return false;
        if (index === word.length - 1) return true;
        board[i][j] = ' ';
        // used[i][j] = true;
        if (dfs(i+1, j,index+1) ||
            dfs(i-1, j,index+1) ||
            dfs(i, j+1,index+1) ||
            dfs(i, j-1,index+1)) return true;
        // used[i][j] = false;
        board[i][j] = word.charAt(index);
        return false;
    }

    for (let i = 0; i < board.length; i++) {// 行
        for (let j = 0; j < board[0].length; j++) {// 列
            if (dfs(i, j,0)) return true;
        }
    }
    return false;
};

100. 相同的树

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的

示例1:
在这里插入图片描述
输入:p = [1,2,3], q = [1,2,3]
输出:true
示例2:
在这里插入图片描述
输入:p = [1,2], q = [1,null,2]
输出:false
示例3:
在这里插入图片描述
输入:p = [1,2,1], q = [1,1,2]
输出:false

解:如果两个二叉树都为空,则两个二叉树相同。如果两个二叉树中有且只有一个为空,则两个二叉树一定不相同。如果两个二叉树都不为空,那么首先判断它们的根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别判断两个二叉树的左子树是否相同以及右子树是否相同。
代码如下:
JS:

var isSameTree = function(p, q) {
    if ((p && !q) || (!p && q)) return false;
    if (!p && !q) return true;
    if (p.val !== q.val) return false;
    return isSameTree(p.left,q.left) && isSameTree(p.right, q.right);
};

剑指 Offer 26. 树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。约定空树不是任意一个树的子结构。B是A的子结构, 即 A中有出现和B相同的结构和节点值。

示例 1:
输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1]
输出:true
示例3:
输入:{8,8,#,9,#,2,#,5},{8,9,#,2}
返回值:true

解:
1.遍历A 找到A中与B的根节点的值相等的节点 然后判断以这个节点构成的A的子树与B是否相同(借鉴上一题的代码 但稍有改动:若q为空 表示q遍历完了 不管p遍没遍历完都返回true p为空或值不相等 返回false) 只有相同才返回true 如果不相同 则继续遍历A 因为A中可能有重复节点(如示例3)

var isSubStructure = function(A, B) {
    if (!A || !B) return false;
    if (A.val === B.val) {
        if (isSameTree(A, B)) return true;
    }
    return isSubStructure(A.left, B) || isSubStructure(A.right, B);
};
var isSameTree = function(p, q) {
    if (!q) return true;// 只要q为空(表示q遍历完了) 则返回true
    if (!p || p.val !== q.val) return false;// p为空或值不等 返回false
    return isSameTree(p.left,q.left) && isSameTree(p.right, q.right);
};

101. 对称二叉树

剑指 Offer 28. 对称的二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
这里是引用
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
在这里插入图片描述

解:如果同时满足下面的条件,两个树互为镜像:

  1. 它们的两个根结点具有相同的值
  2. 根节点的右子树都与另一个根节点的左子树镜像对称 同理 根节点的左子树都与另一个根节点的右子树镜像对称
    所以我们需要定义一个函数 用来判断两个根节点的左/右子树是否相等
    代码如下:
    JS:
var isSymmetric = function(root) {
    if (root === null) return true;
    return isSame(root.left, root.right);
};
var isSame = function (left, right) {
    if (left === null && right === null) return true;
    if (left === null || right === null) return false;
    if (left.val !== right.val) return false;
    return isSame(left.left, right.right) && isSame(left.right, right.left);
}

JAVA:

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        return isSymmetric(root.left,root.right);
    }

    public boolean isSymmetric(TreeNode root1,TreeNode root2) {
        if (root1 == null && root2 == null) return true;
        if (root1 == null && root2 != null) return false;
        if (root1 != null && root2 == null) return false;
        return (root1.val == root2.val) && isSymmetric(root1.left,root2.right) && isSymmetric(root1.right,root2.left
        );
    }
}

102. 二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)

示例:
二叉树:[3,9,20,null,null,15,7],
在这里插入图片描述
返回其层序遍历结果:
[
[3],
[9,20],
[15,7]
]

解:层序遍历 多用一个变量size保存每一层的节点数 当每弹出一个节点size-- 当size为0时将队列长度赋值给size
代码如下:
JS:

if (!root) return [];
    let node;
    let ans = [];
    let queue = [root];
    let size = 1;
    let arr = [];
    while (queue.length) {
        node = queue.shift();
        size--;
        arr.push(node.val);
        node.left && queue.push(node.left);
        node.right && queue.push(node.right);
        if (size === 0) {
            ans.push(arr);
            size = queue.length;
            arr = [];
        }
    }
    return ans;

剑指 Offer 32 - I. 从上到下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

给定二叉树: [3,9,20,null,null,15,7],
在这里插入图片描述
返回:[3,9,20,15,7]

解:层序遍历
代码如下:
JS:

var levelOrder = function(root) {
    if (!root) return [];
    let node;
    let ans = [];
    let queue = [root];
    while (queue.length) {
        node = queue.shift();
        ans.push(node.val);
        // if (node.left) {
        //     queue.push(node.left);
        // }
        // if (node.right) {
        //     queue.push(node.right);
        // }
        //上面的代码可以简化为:
        node.left && queue.push(node.left);
        node.right && queue.push(node.right);
    }
    return ans;
};

剑指 Offer 32 - II. 从上到下打印二叉树 II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

例如:
给定二叉树: [3,9,20,null,null,15,7],
在这里插入图片描述
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]

解:层序遍历 每一层的放入一个数组 每一层遍历完将数组放入答案数组中 清空数组
代码如下
JS

var levelOrder = function(root) {
    if (!root) return [];
    let queue = [root];
    let ans = [];
    let level = [];
    let size = 1;
    let node;
    while (queue.length !== 0) {
        node = queue.shift();
        level.push(node.val);
        size--;
        if (node.left) queue.push(node.left);
        if (node.right) queue.push(node.right);
        if (size === 0) {
            size = queue.length;
            ans.push(level);
            level = [];
        }
    }
    return ans;
};

剑指 Offer 32 - III. 从上到下打印二叉树 III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7]
在这里插入图片描述
返回其层次遍历结果:
[
[3],
[20,9],
[15,7]
]

解:和上一题一样的解法 只不过本题在奇数层使从左往右打印 在偶数层使从右往左打印 那么我们可以设立标志位flag flag=true是正常情况下使奇数层从左往右打印 flag=false是从右往左打印 此时将level数组反转再加入答案数组中即可

var levelOrder = function(root) {
    if (!root) return [];
    let queue = [root];
    let ans = [];
    let level = [];
    let size = 1;
    let node;
    let flag = true;// true代表从左到右打印 false代表从右到左打印
    while (queue.length !== 0) {
        node = queue.shift();
        level.push(node.val);
        size--;
        if (node.left) queue.push(node.left);
        if (node.right) queue.push(node.right);
        if (size === 0) {
            size = queue.length;
            if (flag) {
                flag = false;
            }else {
                level.reverse();
                flag = true;
            }
            ans.push(level);
            level = [];
        }
    }
    return ans;
};

优化)因为在奇数层使从左往右打印 在偶数层使从右往左打印 所以在奇数层我们从数组尾部加入元素 在偶数层我们从数组头部加入元素 然后直接将数组加入答案数组即可 不用设立标志位 在判断奇偶层时 当答案数组的长度为偶数代表现在在奇数层 为奇数代表现在在偶数层
代码如下
JS

var levelOrder2 = function(root) {
    if (!root) return [];
    let queue = [root];
    let ans = [];
    let level = [];
    let size = 1;
    let node;
    while (queue.length !== 0) {
        node = queue.shift();
        if (ans.length % 2 === 0) {
            level.push(node.val);
        }else {
            level.unshift(node.val);
        }
        size--;
        if (node.left) queue.push(node.left);
        if (node.right) queue.push(node.right);
        if (size === 0) {
            size = queue.length;
            ans.push(level);
            level = [];
        }
    }
    return ans;
};

105. 从前序与中序遍历序列构造二叉树

剑指 Offer 07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
在这里插入图片描述

解:
在这里插入图片描述

因为前序遍历的第一个元素就是当前二叉树的根节点。那么,这个值就可以将中序遍历分成 2 个部分:左子树的中序遍历和右子树的中序遍历 再根据左子树的中序遍历的个数将前序遍历分为2部分:左子树的前序遍历和右子树的前序遍历 将左子树的前序遍历 中序遍历传入函数 递归调用得到左子树 将右子树的前序遍历 中序遍历传入函数 递归调用得到右子树
代码如下:
JS:

var buildTree = function(preorder, inorder) {
    if (preorder.length === 0) return null;
    if (preorder.length === 1) return new TreeNode(preorder[0]);
    let root = new TreeNode(preorder[0]);
    let lr;
    for (let i = 0; i < inorder.length; i++) {
        if (inorder[i] === root.val){
            lr = i;
            break;
        }
    }
    root.left = buildTree(preorder.slice(1, 1 + lr), inorder.slice(0, lr));
    root.right = buildTree(preorder.slice(1 + lr, preorder.length), inorder.slice(lr + 1, inorder.length));
    return root;
};

113. 路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。

示例1:
在这里插入图片描述
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例2:
在这里插入图片描述
输入:root = [1,2,3], targetSum = 5
输出:[]
示例3:
输入:root = [1,2], targetSum = 0
输出:[]

解:
深度优先搜索+回溯
代码如下:
JS:

var pathSum = function(root, targetSum) {
    if (!root) return [];
    let ans = [];
    let arr = [root.val];
    targetSum -= root.val;
    dfs(root, targetSum, ans, arr);
    return ans;
};
var dfs = function (root, targetSum, ans, arr) {
    if (!root.left && !root.right && targetSum === 0) {
        ans.push(arr.slice());
        return;
    }
    if (root.left) {
        targetSum -= root.left.val;
        arr.push(root.left.val);
        dfs(root.left, targetSum, ans, arr);
        targetSum += root.left.val;
        arr.pop();
    }
    if (root.right) {
        targetSum -= root.right.val;
        arr.push(root.right.val);
        dfs(root.right, targetSum, ans, arr);
        targetSum += root.right.val;
        arr.pop();
    }

}

200. 岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。

示例 1:
输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1
示例 2:
输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3

解:
1.目标是找到矩阵中 “岛屿的数量” ,上下左右相连的 1 都被认为是连续岛屿。
2.设目前指针指向一个岛屿中的某一点 (i, j),寻找包括此点的岛屿边界。
3.从 (i, j) 向此点的上下左右 (i+1,j),(i-1,j),(i,j+1),(i,j-1) 做深度搜索。
4.终止条件:
(1)(i, j) 越过矩阵边界;
(2)grid[i][j] == 0,代表到达岛屿边界。
5.搜索岛屿的同时,执行 grid[i][j] = ‘0’,即将岛屿所有节点删除,以免之后重复搜索相同岛屿。
6.主循环:遍历整个矩阵,当遇到 grid[i][j] == ‘1’ 时,从此点开始做深度优先搜索 dfs,岛屿数 count + 1 且在深度优先搜索中删除此岛屿。
7.最终返回岛屿数 count 即可。
代码如下:
JAVA:

class Solution {
    public int numIslands(char[][] grid) {
        int count = 0;
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[0].length; j++) {
                if(grid[i][j] == '1'){
                    dfs(grid, i, j);
                    count++;
                }
            }
        }
        return count;
    }
    private void dfs(char[][] grid, int i, int j){
        if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
        grid[i][j] = '0';
        dfs(grid, i + 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i - 1, j);
        dfs(grid, i, j - 1);
    }
}

226. 翻转二叉树

剑指 Offer 27. 二叉树的镜像

翻转一棵二叉树。

输入:
在这里插入图片描述
输出:
在这里插入图片描述

解:交换root的左右节点的位置 将左/右节点作为根节点传入函数 交换左/右节点的左右节点的位置
代码如下:
JS:

var invertTree = function(root) {
    if (!root) return root;
    let node = root.left;
    root.left = root.right;
    root.right = node;
    invertTree(root.left);
    invertTree(root.right);
    return root;
};

剑指 Offer 33. 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

这里是引用
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true

解:
1.划分左右子树: 遍历后序遍历的[i,j] 区间元素,寻找第一个大于根节点 的节点,索引记为m。此时,可划分出左子树区间[i,m−1] 、右子树区间[m,j−1] 、根节点索引j。
2.判断是否为二叉搜索树:
左子树区间[i,m−1]内的所有节点都应 < postorder[j]。而第 1.划分左右子树 步骤已经保证左子树区间的正确性,因此只需要判断右子树区间即可。
右子树区间[m,j−1] 内的所有节点都应 > postorder[j]。实现方式为遍历,当遇到≤postorder[j] 的节点则跳出,返回false;则可通过p=j判断是否为二叉搜索树。

剑指 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。请问该机器人能够到达多少个格子?

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

解:只用向右 向下两个方向走就可以走完整个数组
在这里插入图片描述
代码如下:
JS

var movingCount = function(m, n, k) {
    if (k === 0) return 1;
    let ans = 0;
    let arr = Array.from(new Array(m),() => new Array(n).fill(false));
    let res = function (i, j) {
        if (i >= m || j >= n || arr[i][j] || (i % 10 + Math.floor(i / 10) + j % 10 + Math.floor(j / 10) > k)) return;
        ans++;
        arr[i][j] = true;
        res(i + 1, j);
        res(i, j + 1);
    }

    res(0, 0);
    return ans;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值