DFS算法-leetcode java题解

news2024/11/28 13:53:07

DFS算法-leetcode java题解

本文目录

    • DFS算法-leetcode java题解
      • leetcode 547. 省份数量
      • leetcode 463. 岛屿的周长
      • leetcode 200. 岛屿数量
      • leetcode 130. 被围绕的区域
      • leetcode 417. 太平洋大西洋水流问题
      • leetcode 17. 电话号码的字母组合
      • leetcode 22. 括号生成
      • leetcode 39. 组合总和
      • leetcode 46. 全排列
      • leetcode 78. 子集
      • leetcode 90. 子集 II
      • leetcode 77. 组合
      • leetcode 216. 组合总和 III
      • leetcode 257. 二叉树的所有路径
      • leetcode 93. 复原 IP 地址
      • leetcode 79. 单词搜索
      • leetcode 131. 分割回文串
      • leetcode 51. N 皇后
      • leetcode 37. 解数独
      • leetcode 473. 火柴拼正方形

dfs本质是递归

从一个节点出发,使用 DFS 对一个图进行遍历时,能够遍历到的节点都是从初始节点可达的

Backtracking(回溯)属于 DFS。

  • 普通 DFS 主要用在 可达性问题 ,这种问题只需要执行到特点的位置然后返回即可。
  • 回溯(Backtracking)主要用于求解 排列组合 问题,例如有 { ‘a’,‘b’,‘c’ } 三个字符,求解所有由这三个字符排列得到的字符串,这种问题在执行到特定的位置返回之后还会继续执行求解过程
public void dfs(int[] candidates, int target,int index, List<Integer> res) {
    // 终止递归的条件
    if (target == 0) {
        ans.add(new ArrayList(res));
        return;
    }
    //
    for (int i = index; i < candidates.length; i++) {
        if (target - candidates[i] >= 0) { // 根据题意 剪枝条件,此处只是举例
            res.add(candidates[i]);
            dfs(candidates, target - candidates[i],i, res);
            // 需要删除最后一个叶子节点的结果,返回上一层在遍历其他的结果
            res.remove(res.size() - 1); 
        }
    }
}

leetcode 547. 省份数量

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2

输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3

多个不连通的图,分别深度遍历

    public int findCircleNum(int[][] isConnected) {
        if(isConnected == null || isConnected.length == 0){
            return 0;
        }
        int n = isConnected.length;
        boolean[] visited = new boolean[n];// 定义 boolean 数组标识顶点是否被访问
        int circle = 0;// 定义 circle 来累计遍历过的连通域的数量
        for(int i = 0; i < n; i++){
            // 若当前顶点 i 未被访问,说明又是一个新的连通域,则遍历新的连通域且circle+=1.
            if( !visited[i]){
                dfs(isConnected, i, visited);
                circle ++;
            }
        }
        return circle;
    }

    private void dfs(int[][] isConnected, int i, boolean[] visited){
        int n = isConnected.length;
        // 对当前顶点 i 进行访问标记
        visited[i] = true;
        for(int j = 0; j < n; j ++){
            // 继续遍历与顶点 i 相邻的顶点(使用 visited 数组防止重复访问)
            if(isConnected[i][j] == 1 && !visited[j]){
                dfs(isConnected, j, visited);
            }
        }
    }

leetcode 463. 岛屿的周长

给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。

网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。

岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。

输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16
解释:它的周长是上面图片中的 16 个黄色的边

输入:grid = [[1]]
输出:4

输入:grid = [[1,0]]
输出:4

遇到四个边界或者水域,边长+1

    int[][] directions = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    int res = 0;
    public int islandPerimeter(int[][] grid) {
        if(grid == null || grid.length == 0){
            return 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);
                }
            }
        }
        return res;
    }

    private void dfs(int[][] grid, int r, int c) {
        if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length || grid[r][c] == 0) {
            res ++;
            return;
        }

        if(grid[r][c] == 2){
            return;
        }
        
        grid[r][c] = 2;
        for(int[] dir : directions){
            dfs(grid, r + dir[0], c + dir[1]);
        }
    }

leetcode 200. 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

输入:grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出:3
    int[][] directions = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    public int numIslands(char[][] grid) {
        int ans = 0;
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j < grid[0].length; j++){
                if(grid[i][j] == '1'){
                    ans ++;
                    dfs(grid, i, j);
                }
            }
        }
        return ans;
    }

    private void dfs(char[][] grid, int r, int c) {
        if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length || grid[r][c] == '0') {
            return;
        }

        if(grid[r][c] == '2'){
            return;
        }
        grid[r][c] = '2';
        for(int[] dir : directions){
            dfs(grid, r + dir[0], c + dir[1]);
        }
    }

leetcode 130. 被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]
输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

从边界开始进行深度遍历,所有遍历的都是不需要修改的,记录即可

    public void solve(char[][] board) {
        int m = board.length;
        int n = board[0].length;

        for (int i = 0; i < m; i++) {
            if (board[i][0] == 'O') {
                dfs(board, i, 0);
            }
            if (board[i][n-1] == 'O') {
                dfs(board, i, n-1);
            }
        }
        for (int j = 0; j < n; j++) {
            if (board[0][j] == 'O') {
                dfs(board, 0, j);
            }
            if (board[m-1][j] == 'O') {
                dfs(board, m-1, j);
            }
        }

        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                if(board[i][j] == 'O') 
                    board[i][j] = 'X';
                if(board[i][j] == 'Y') 
                    board[i][j] = 'O';    
            }
        }

    }

    private void dfs(char[][] grid, int r, int c) {
        int[][] directions = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
        // 判断 base case
        if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length || grid[r][c] != 'O') {
            return;
        }

        if(grid[r][c] == 'O'){
            grid[r][c] = 'Y';
        }

        for(int[] dir : directions){
            dfs(grid, r + dir[0], c + dir[1]);
        }

    }

leetcode 417. 太平洋大西洋水流问题

有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。

这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , heights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度 。

岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。

返回网格坐标 result 的 2D 列表 ,其中 result[i] = [ri, ci] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可流向大西洋 。
输入: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
输出: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]

输入: heights = [[2,1],[1,2]]
输出: [[0,0],[0,1],[1,0],[1,1]]

从海域到格子按照从低到高(非严格)顺序

使用两遍 DFS进行求解:分别从与当前海域直接相连的边缘格子出发,统计能够流向当前海域的格子集合,两片海域求得的集合交集即是答案。

class Solution {
    int[][] directions = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    public List<List<Integer>> pacificAtlantic(int[][] heights) {
        int m = heights.length, n = heights[0].length;
        boolean[][] res1 = new boolean[m][n], res2 = new boolean[m][n];
        for(int i = 0; i < heights.length; i++){
            for(int j = 0; j < heights[0].length; j++){
                if (i == 0 || j == 0) {
                    if (!res1[i][j]) dfs(heights, i, j, res1);
                }
                if (i == m - 1 || j == n - 1) {
                    if (!res2[i][j]) dfs(heights, i, j, res2);
                }
            }
        }

        List<List<Integer>> ans = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (res1[i][j] && res2[i][j]) {
                    List<Integer> list = new ArrayList<>();
                    list.add(i); list.add(j);
                    ans.add(list);
                }
            }
        }
        return ans;
    }

    private void dfs(int[][] grid, int r, int c, boolean[][] res) {
        res[r][c] = true;
        for(int[] dir : directions){
            int nx = r + dir[0], ny = c + dir[1];
            if (nx < 0 || nx >= grid.length || ny < 0 || ny >= grid[0].length) {
                continue;
            }
            if (res[nx][ny] || grid[nx][ny] < grid[r][c]) {
                continue;
            }
            dfs(grid, r + dir[0], c + dir[1], res);
        }
    }
    
}

leetcode 17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

输入:digits = ""
输出:[]

对String的处理使用StringBuilder

回溯
sb.setLength(sb.length() - 1);
sb.deleteCharAt(sb.length()-1);

    public List<String> letterCombinations(String digits) {
        String[] map = new String[]{"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        StringBuilder sb = new StringBuilder();
        List<String> res = new ArrayList<>();

        if(digits == null || digits.length() == 0) return res;
        dfs(map, sb, res, digits, 0);
        return res;
    }

    public void dfs(String[] map, StringBuilder sb, List<String> res, String digits, int index){
        if(sb.length() == digits.length()){
            res.add(sb.toString());
            return;
        }

        String now = map[digits.charAt(index)-'2'];
        for(char ch: now.toCharArray()){
            sb.append(ch);
            dfs(map, sb, res, digits,index+1);
            //找完了,回退结果
            sb.deleteCharAt(sb.length()-1);
        }
    }

leetcode 22. 括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

输入:n = 1
输出:["()"]
    public List<String> generateParenthesis(int n) {
        List<String> res = new LinkedList<>();
        StringBuilder sb = new StringBuilder();
        dfs(n, n, sb, res);

        return res;
    }

    public void dfs(int left, int right, StringBuilder sb, List<String> res){
        if(left < 0 || right < 0 || right < left) return;

        if(left == 0 && right == 0){
            res.add(sb.toString());
        }

        sb.append('(');
        dfs(left-1, right, sb, res);
        sb.setLength(sb.length() - 1);

        sb.append(')');
        dfs(left,right-1, sb, res);
        sb.setLength(sb.length() - 1);

    }

leetcode 39. 组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

回溯
list.add(candidates[i]);
list.remove(list.size()-1);

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        dfs(res, list, candidates, target, 0);
        return res;
    }

    public void dfs(List<List<Integer>> res, List<Integer> list, int[] candidates, int target, int n){
        if(target < 0) return;

        if(target == 0){
            res.add(new ArrayList(list));
            return;
        }

        for(int i = n; i < candidates.length; i++){
            list.add(candidates[i]);
            dfs(res, list, candidates, target - candidates[i], i);
            list.remove(list.size()-1);
        }

    }

leetcode 46. 全排列

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

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

输入:nums = [0,1]
输出:[[0,1],[1,0]]

通过list是否存在此元素来剪枝

    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        dfs(res, list, nums);
        return res;
    }

    public void dfs(List<List<Integer>> res, List<Integer> list, int[] nums){
        if(nums.length == list.size()){
            res.add(new ArrayList(list));
            return;
        }

        for(int i = 0; i < nums.length; i++){
            if(list.contains(nums[i])) continue;
            list.add(nums[i]);
            dfs(res, list, nums);
            list.remove(list.size()-1);
        }

    }

leetcode 78. 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        dfs(res, list, nums, 0);
        return res;
    }

    public void dfs(List<List<Integer>> res, List<Integer> list, int[] nums, int start){
        //中间的每一步都存
        res.add(new ArrayList(list));
        
        //遍历了 i ,所有带i的子集就都找完了
        for(int i = start; i < nums.length; i++){
            list.add(nums[i]);
            dfs(res, list, nums, i+1);
            list.remove(list.size()-1);
        }

    }

leetcode 90. 子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

先排序,再使用HashSet去重

class Solution {
    Set<List<Integer>> ans = new HashSet<>();
    List<Integer> temp = new LinkedList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        dfs(nums, 0);
        List<List<Integer>> ans1 = new LinkedList<>();
        for(List<Integer> temp : ans) {
            ans1.add(temp);
        }
        return ans1;
    }

    private void dfs(int[] nums, int index) {
        ans.add(new ArrayList(temp));

        for(int i = index; i < nums.length; i++){
            temp.add(nums[i]);
            dfs(nums, i+1);
            temp.remove(temp.size()-1);
        }

    }
}

leetcode 77. 组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

剪枝策略:搜索起点的上界 = n - (k - path.size()) + 1

class Solution {
    List<List<Integer>> ans = new LinkedList<>();
    List<Integer> temp = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        dfs(n, k, 1);
        List<List<Integer>> ans1 = new LinkedList<>();
        for(List<Integer> temp : ans) {
            ans1.add(temp);
        }
        return ans1;
    }

    private void dfs(int n, int k, int start) {
        if(temp.size() == k){
            ans.add(new ArrayList(temp));
            return;
        }

        if(temp.size() > k){
            return;
        }

        //for(int i = start; i <= n; i++)  -- 未剪枝
        for(int i = start; i <= n - (k - temp.size()) + 1; i++){
            temp.add(i);
            dfs(n, k, i+1);
            temp.remove(temp.size()-1);
        }

    }
}

leetcode 216. 组合总和 III

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

只使用数字1到9
每个数字 最多使用一次 
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。
class Solution {
    List<List<Integer>> ans = new LinkedList<>();
    List<Integer> temp = new LinkedList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        dfs(k, 1, n);
        return ans;
    }

    private void dfs(int n, int start, int rest) {
        if(temp.size() == n && rest == 0){
            ans.add(new ArrayList(temp));
            return;
        }

        if(temp.size() > n){
            return;
        }

        int mm = Math.min(rest, 9);
        for(int i = start; i <= mm; i++){
            temp.add(i);
            dfs(n, i+1, rest-i);
            temp.remove(temp.size()-1);
        }

    }
}

leetcode 257. 二叉树的所有路径

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();
        dfs(root, "", res);
        return res;
    }

    public void dfs(TreeNode root, String path, List<String> res) {
        if (root == null)
            return;

        if (root.left == null && root.right == null) {
            res.add(path + root.val);
            return;
        }

        dfs(root.left, path + root.val + "->", res);
        dfs(root.right, path + root.val + "->", res);
    }
}

leetcode 93. 复原 IP 地址

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

使用List存储中间结果段,最后拼接起来

与普通的dfs结束不同,最后一个字符需要加入后再判断,所以判断处使用index == s.length(),最后一个字符加入后的下一次dfs才存储

class Solution {
    List<String> sans = new LinkedList<>();
    public List<String> restoreIpAddresses(String s) {
        dfs(s, 0, new LinkedList<>());
        return sans;
    }

    private void dfs(String s, int index, List<String> temp) {
        if (temp.size() == 4 && index == s.length()) {
            sans.add(String.join(".", temp));
            return;
        }

        for(int i = 1; i <= 3; i++){
            if (index + i > s.length()) {
                break;
            }

            String segment = s.substring(index, index + i);
            int val = Integer.valueOf(segment);
            if ((segment.startsWith("0") && segment.length() > 1) || (i == 3 && val > 255)) {
                continue;
            }

            temp.add(segment);
            dfs(s, index + i, temp);
            temp.remove(temp.size()-1);
        }

    }
}

leetcode 79. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true

从开头字母的位置开始遍历

使用flag记录已遍历和回溯

class Solution {
    int[][] flag;
    public boolean exist(char[][] board, String word) {
        flag = new int[board.length][board[0].length];
        char st = word.charAt(0);
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == st) {
                    if(dfs(board, word, i, j, 0)){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    int[][] directions = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
    private boolean dfs(char[][] board, String word, int r, int c, int k) {
        if (r < 0 || r >= board.length || c < 0 || c >= board[0].length || flag[r][c] == 1) {
            return false;
        }
        if (board[r][c] != word.charAt(k)) {
            return false;
        }
        if (k == word.length()-1) {
            return true;
        }

        flag[r][c] = 1;
        boolean rm = false;
        for(int[] dir : directions){
            if(dfs(board, word,r + dir[0], c + dir[1], k+1)){
                rm = true;
                break;
            }
        }
        flag[r][c] = 0;
        return rm;

    }
}

leetcode 131. 分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
class Solution {
    List<List<String>> ans = new LinkedList<>();
    List<String> temp = new LinkedList<>();
    public List<List<String>> partition(String s) {
        dfs(s, 0);
        return ans;
    }

    private void dfs(String s, int index) {
        if (index == s.length()) {
            ans.add(new ArrayList<>(temp));
            return;
        }

        for(int i = index+1; i <= s.length(); i++){
            String segment = s.substring(index, i);
            if(!isHui(segment)){
                continue;
            }
            temp.add(segment);
            dfs(s, i);
            temp.remove(temp.size()-1);
        }
    }

    public boolean isHui(String str){
        int l = str.length();
        for(int i = 0; i < l/2; i++){
            if(str.charAt(i) != str.charAt(l-i-1)){
                return false;
            }
        }
        return true;
    }

}

leetcode 51. N 皇后

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。


输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
    public List<List<String>> solveNQueens(int n) {
        char[][] chess = new char[n][n];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                chess[i][j] = '.';
        List<List<String>> ans = new LinkedList<>();
        dfs(ans, chess, 0);
        return ans;

    }

    private void dfs(List<List<String>> ans, char[][] chess, int row) {
        if (row == chess.length) {
            ans.add(construct(chess));
            return;
        }
        for (int col = 0; col < chess.length; col++) {
            if (valid(chess, row, col)) {
                chess[row][col] = 'Q';
                dfs(ans, chess, row + 1);
                chess[row][col] = '.';
            }
        }

    }

    //row表示第几行,col表示第几列
    private boolean valid(char[][] chess, int row, int col) {
        //坐标位置的上面有没有皇后
        for (int i = 0; i < row; i++) {
            if (chess[i][col] == 'Q') {
                return false;
            }
        }
        //判断当前坐标的右上角有没有皇后
        for (int i = row - 1, j = col + 1; i >= 0 && j < chess.length; i--, j++) {
            if (chess[i][j] == 'Q') {
                return false;
            }
        }
        //判断当前坐标的左上角有没有皇后
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (chess[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }

    //把数组转为list
    private List<String> construct(char[][] chess) {
        List<String> path = new ArrayList<>();
        for (int i = 0; i < chess.length; i++) {
            path.add(new String(chess[i]));
        }
        return path;
    }

leetcode 37. 解数独

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。
class Solution {
    public void solveSudoku(char[][] board) {
        dfs(board);
    }

    public boolean dfs(char[][] board){
        for (int i = 0; i < 9; i++){
            for (int j = 0; j < 9; j++){
                if (board[i][j] != '.'){
                    continue;
                }
                for (char k = '1'; k <= '9'; k++){
                    if (panduan(i, j, k, board)){
                        board[i][j] = k;
                        if (dfs(board)){
                            return true;
                        }
                        board[i][j] = '.';
                    }
                }
                return false;
            }
        }

        return true;

    }

    public boolean panduan(int row, int col, char val, char[][] board){
        for(int i = 0; i < 9; i++){
            if (board[row][i] == val){
                return false;
            }
        }

        for (int j = 0; j < 9; j++){
            if (board[j][col] == val){
                return false;
            }
        }

        int startRow = (row / 3) * 3;
        int startCol = (col / 3) * 3;
        for (int i = startRow; i < startRow + 3; i++){
            for (int j = startCol; j < startCol + 3; j++){
                if (board[i][j] == val){
                    return false;
                }
            }
        }

        return true;

    }
}

leetcode 473. 火柴拼正方形

你将得到一个整数数组 matchsticks ,其中 matchsticks[i] 是第 i 个火柴棒的长度。你要用 所有的火柴棍 拼成一个正方形。你 不能折断 任何一根火柴棒,但你可以把它们连在一起,而且每根火柴棒必须 使用一次 。

如果你能使这个正方形,则返回 true ,否则返回 false 。

输入: matchsticks = [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。

把正方形的四条边看成从上到下四条一样的线,每个火柴去每条线段中匹配

class Solution {
    public boolean makesquare(int[] matchsticks) {
        Arrays.sort(matchsticks);
        int len = 0;
        int maxl = 0;
        for(int i = 0; i < matchsticks.length; i++){
            len += matchsticks[i];
            maxl = Math.max(maxl, matchsticks[i]);
        }
        if(len % 4 != 0 || maxl > len / 4){
            return false;
        }

        return dfs(matchsticks, matchsticks.length - 1, len / 4, new int[4]);
    }

    public boolean dfs(int[] nums, int index, int target, int[] size){
        if (index == -1) {
            if (size[0] == size[1] && size[1] == size[2] && size[2] == size[3])
                return true;
            return false;
        }

        for (int i = 0; i < size.length; i++) {
            if (size[i] + nums[index] > target)
                continue;
            size[i] += nums[index];
            if (dfs(nums, index - 1, target, size))
                return true;
            size[i] -= nums[index];
        }

        return false;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142761.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

List 容器的接口使用、迭代器失效(仅erase)

目录 一、接口使用 ① 构造函数 ②迭代器 ③ 容量与元素修改 ④ remove ⑤remove_if ⑥ unique ⑦sort&#xff08;&#xff09; ⑧ merge() 二、对于迭代器失效问题 一、接口使用 ① 构造函数 void MyListTest1() {list<int> l1;list<int> l5(10, 5);vector…

〖产品思维训练白宝书 - 产品思维认知篇⑦〗- 聊一聊 产品经理 的工作内容与职责划分

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…

自定义类型【c语言】

前言&#xff1a; c语言提供了丰富的内置类型&#xff0c;但是在描述一些复杂对象的时候仍不能满足一定的功能&#xff0c;因此c语言为了支持我们能描述一些复杂对象给出了我们能自定义的一些类型&#xff0c;因此便有了自定义类型。 在之前我们已经初步对结构体进行相应的了解…

提升工作效率,领导都夸的开源数据可视化工具

echarts官网有很多好看的图例&#xff0c;怎么结合起来放到自己的项目中呢&#xff1f;比如这种酷酷的首页&#xff1a; 这种看起来美观又大方&#xff0c;自己要是能用上就好了。 其实这是可以的&#xff0c;echarts上有现成的图例和示例代码&#xff0c;咱们只要改改数据源就…

华为防火接与二层交换机对接配置VLAN上网设置

拓扑图 一、防火墙设置 1、G1/0/0接口设置IP&#xff0c;G1/0/1接口切换二层口设置VLAN&#xff0c;G1/0/0 桥接了本地无线网卡来模拟外网地址 <USG6000V1>sys [USG6000V1]sys FW1 [FW1]un in en# 设置外网IP [FW1]int g1/0/0 [FW1-GigabitEthernet1/0/0]ip addr 192.1…

ORB-SLAM2 --- LocalMapping::SearchInNeighbors函数

0.函数更新内容 仅对地图点进行融合。 1.函数作用 检查并融合当前关键帧与相邻帧&#xff08;两级相邻&#xff09;重复的地图点。 2.函数步骤 Step 1&#xff1a;获得当前关键帧在共视图中权重排名前nn的邻接关键帧 Step 2&#xff1a;存储一级相邻关键帧及其二级相邻关键帧 将…

Java变量的作用域:静态变量、全局变量和局部变量

变量的作用域规定了变量所能使用的范围&#xff0c;只有在作用域范围内变量才能被使用。根据变量声明地点的不同&#xff0c;变量的作用域也不同。根据作用域的不同&#xff0c;一般将变量分为不同的类型&#xff1a;成员变量和局部变量。下面对这几种变量进行详细说明。成员变…

代码随想录训练营第四十二天

1.背包问题 1.1 01背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 1.1.1 用动态规划的方法解决------二维dp数组01背包 ①确定dp…

学一下这个60秒的男人

程序员求职简历&#xff0c;项目经验怎么写&#xff1f;免费修改简历、提供模板并内部推荐今天想跟大家聊一下这个“60秒”的男人。10月21日&#xff0c;罗辑思维发文&#xff1a;《罗胖60秒&#xff1a;10年期满&#xff0c;今日告别》。10年前&#xff0c;罗振宇开始干一件事…

智能防雷,智能防雷系统的应用研究方案

“智慧智能防雷”是近年来防雷界提出的一个全新的防雷理念&#xff0c;是防雷业发展的趋势。所谓“智慧智能防雷”&#xff0c;是将大数据分析、云存储、人工智能、移动互联网和物联网技术融入到传统防雷措施中&#xff0c;并通过软、硬件系统的集成&#xff0c;实现对特定的区…

企业微信收款后可以进行退款吗?如何操作?

很多企业使用企业微信运营&#xff0c;就是看中了企业微信对外收款的功能&#xff0c;它不仅简化了转账步骤&#xff0c;而且可以在必要时直接完成退款&#xff0c;操作简单方便。前言随着企业微信的普及度&#xff0c;越来越多的企业认识到企业微信运营功能的强大&#xff0c;…

带你了解2023新版本Internet Download Manager有哪些新功能优势

作为一款体积只有10M的下载软件&#xff0c;IDM却常年霸占着各软件评测榜的前列。它的界面简洁清爽&#xff0c;使用过程中无弹窗、无广告&#xff0c;小小的体积竟能将下载速度提升5倍&#xff01;该软件一进入中国市场&#xff0c;便受到了广大用户的追捧&#xff0c;被大家亲…

2023年留学基金委(CSC)联合培养博士研究生项目解读及建议

近日&#xff0c;国家留学基金委&#xff08;CSC&#xff09;公布了2023年国家建设高水平大学公派研究生项目&#xff0c;该项目分为两部分&#xff0c;1.申请攻读博士学位研究生&#xff1b;2.申请联合培养博士研究生。本文知识人网小编仅就联合培养博士研究生部分进行解读&am…

【生信】R语言进行id转换的方法(附可直接使用代码)

本文我都默认已经下载好了表达矩阵exp了哦 代码都是直接给出来了&#xff0c;需要修改的地方我进行了标记 一般只要修改一下都能直接用了 方法一&#xff1a;下载平台数据以得到对应信息 然后进入官网https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi&#xff0c;在这里我以G…

【数据结构】4.4 数组

4.4.1 数组的定义 数组&#xff1a; 按照一定格式排列起来的&#xff0c;具有相同类型的数据元素的集合。 一维数组&#xff1a; 若线性表中的数据元素为非结构的简单元素&#xff0c;则称为一维数组。逻辑结构&#xff1a;线性结构&#xff0c;固定长度的线性表。声明格式…

如何学习微服务架构?(项目学习)

哪些项目适合使用微服务架构&#xff1f;对于一般的公司来说&#xff0c;微服务的实践有着很大的技术挑战&#xff0c;所以并不是所有的公司都适合将整体架构拆分成微服务架构。一般来说&#xff0c;微服务架构更适合于未来具有一定扩展复杂度、具有大量增量用户期望的应用&…

最新综述:基于语言模型提示学习的推理

©PaperWeekly 原创 作者 | OE-Heart引言推理能力是人类智能的核心能力之一。随着预训练技术的不断发展&#xff0c;大模型辅之以提示学习&#xff08;如 Chain-of-Thought Prompting [1]&#xff09;涌现出一系列的惊人的推理能力&#xff0c;引起了学术界、工业界学者的…

动态规划——数位dp

数位dp 文章目录数位dp概述题目特征基本原理计数技巧模板例题度的数量思路代码数字游戏思路代码不要62思路代码概述 数位是指把一个数字按照个、十、百、千等等一位一位地拆开&#xff0c;关注它每一位上的数字。如果拆的是十进制数&#xff0c;那么每一位数字都是 0~9&#xf…

unity 前向渲染 渲染阴影原理

下面情况默认是 前向渲染路径&#xff0c;场景中平行光开启了阴影方式原理备注ShadowMap把相机放到光源的位置&#xff0c;那么场景中该光源的阴影区域就是那些相机看不到的位置得到的是&#xff1a;场景中距离光源最近的表面位置&#xff08;深度信息&#xff09;unity中专门的…

一个基于SpringBoot+vue的学生信息管理系统详细设计

一个基于SpringBootvue的学生信息管理系统详细设计 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码…