leetcode刷题第25天——1219,17,22,79

第二十五天

1219 黄金矿工

你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格grid进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是0

为了使收益最大化,矿工需要按以下规则来开采黄金:

  • 每当矿工进入一个单元,就会收集该单元格中的所有黄金。
  • 矿工每次可以从当前位置向上下左右四个方向走。
  • 每个单元格只能被开采(进入)一次。
  • **不得开采(进入)**黄金数目为 0的单元格。
  • 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。
方法

遍历每一个格子,如果当前正在遍历的格子的值不是0,使用DFS搜索一遍答案,当到底时,更新答案。回溯时需要还原现场,因此需要将之前置为true的格子重新置为false,这样才能保证所有的路径都能够被遍历到。(区别于求岛屿最大面积)。

class Solution {
    public static int ans;
    public static boolean[][] isVisited;
    public static int[] dX = {0, 0, 1, -1};
    public static int[] dY = {1, -1, 0, 0};
    public static int xLength;
    public static int yLength;

    public int getMaximumGold(int[][] grid) {
        ans = 0;
        xLength = grid.length;
        yLength = grid[0].length;
        isVisited = new boolean[xLength][yLength];
        for (int i = 0; i < xLength; ++i){
            for (int j = 0; j < yLength; ++j){
                if (grid[i][j] != 0){
                    deepFirstSearch(i, j, grid, grid[i][j]);
                }
            }
        }
        return ans;
    }
    

    public static void deepFirstSearch(int x, int y, int[][] grid, int value){
        isVisited[x][y] = true;
        if (reachBottom(x, y, grid)){
            ans = Math.max(ans, value);
            return;
        }
        for (int i = 0; i < 4; ++i){
            int newX = x + dX[i];
            int newY = y + dY[i];
            if (isValid(newX, newY) && !isVisited[newX][newY] && grid[newX][newY] != 0){
                deepFirstSearch(newX, newY, grid, value + grid[newX][newY]);
                isVisited[newX][newY] = false;//让所有的路径都能够被遍历到
            }
        }
        //遍历所有路径(同一个格子能够被访问多次)
        isVisited[x][y] = false;
    }

    public static boolean isValid(int x, int y){
        return x >= 0 && x < xLength && y >= 0 && y < yLength;
    }
	
    //是否到底了
    public static boolean reachBottom(int x, int y, int[][] grid){
        for (int i = 0; i < 4; ++i){
            if (isValid(x + dX[i], y + dY[i]) && grid[x + dX[i]][y + dY[i]] != 0){
                if (!isVisited[x + dX[i]][y + dY[i]]) return false;
            }
        }
        return true;
    }
}

17 电话号码的组合

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

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

方法

使用DFS遍历所有情况,current变量代表着当前的递归层次,当递归层次和数字长度一样时,返回结果。

class Solution {
    public static char[][] numberOfCharacters;
    public static StringBuilder sb;
    public static ArrayList<String> res;

    public List<String> letterCombinations(String digits) {
        if (digits.length() == 0) return new ArrayList<>();
        res = new ArrayList<>();
        numberOfCharacters = new char[10][];
        numberOfCharacters[2] = new char[]{'a', 'b', 'c'};
        numberOfCharacters[3] = new char[]{'d', 'e', 'f'};
        numberOfCharacters[4] = new char[]{'g', 'h', 'i'};
        numberOfCharacters[5] = new char[]{'j', 'k', 'l'};
        numberOfCharacters[6] = new char[]{'m', 'n', 'o'};
        numberOfCharacters[7] = new char[]{'p', 'q', 'r', 's'};
        numberOfCharacters[8] = new char[]{'t', 'u', 'v'};
        numberOfCharacters[9] = new char[]{'w', 'x', 'y', 'z'};
        sb = new StringBuilder();
        deepFirstSearch(0, numberOfCharacters, digits);
        return res;
    }

    public static void deepFirstSearch(int current ,char[][] chars, String digits){
        if (current == digits.length()){
            res.add(sb.toString());
            return;
        }
        for (char i : chars[digits.charAt(current) - '0']){
            sb.append(i);
            deepFirstSearch(current + 1, chars, digits);
            sb.deleteCharAt(sb.length() - 1);//进行回溯
        }
    }
}

22 括号的生成

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

方法

朴素的方法是使用DFS直接遍历长为2*n的括号序列,同时判断括号序列是否合法,如果合法将其加入到答案中去。这个过程可以进行剪枝优化,具体的方法是,如果当前待加入答案的序列的左括号数量比右括号数量少,这表明这样的括号序列一定不合法。在遍历的过程中,一直维护好leftright变量,当rightleft相等,同时递归层次达到了2*n,就将结果加入到答案中去。

class Solution {

    public static ArrayList<String> res;
    public static StringBuilder sb;
    public static int N;
    public static int left = 0;
    public static int right = 0;

    public List<String> generateParenthesis(int n) {
        N = n;
        sb = new StringBuilder();
        res = new ArrayList<>();
        deepFirstSearch(0, new char[]{'(', ')'});
        return res;
    }

    public static void deepFirstSearch(int current, char[] chars){
        if (current == 2 * N){
            if (left == right){
                res.add(sb.toString());
            }
            return;
        }
        for (char i : chars){
            sb.append(i);
            if (i == '(') ++left;
            else ++right;
            if (left < right){ //不合法 剪枝回溯
                sb.deleteCharAt(sb.length() - 1);
                right--;
                continue;
            }
            deepFirstSearch(current + 1, chars);
            if (i == '(') --left;
            else --right;
            sb.deleteCharAt(sb.length() - 1);

        }
    }
}

79 单词搜索

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

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

方法

使用DFS搜索整个网格,同时进行贪心的选择,只有当下一个要选择的字符和word的下一个字符相同,才进入下一层递归,否则就说明当前层的递归找不到答案,直接返回。

class Solution {
    public static int[] dx = {0, 0, 1, -1};
    public static int[] dy = {1, -1, 0, 0};
    public static boolean[][] isVisited;
    public static boolean res;
    public static int xLength;
    public static int yLength;

    public boolean exist(char[][] board, String word) {
        res = false;
        xLength = board.length;
        yLength = board[0].length;
        if (xLength == 1 && yLength == 1 && word.length() == 1) return board[0][0] == word.charAt(0);
        isVisited = new boolean[board.length][board[0].length];
        for (int i = 0; i < xLength; ++i){
            for (int j = 0; j < yLength; ++j){
                if (board[i][j] == word.charAt(0)) deepFirstSearch(0, i, j, board, word);
            }
        }
        return res;
    }

    public static void deepFirstSearch(int depth, int x, int y, char[][] board, String word){
        isVisited[x][y] = true;
        if (depth == word.length() - 1) {//如果这样的序列长度达到了要求 说明已经找到答案
            res = true;
            return;
        }
        for (int i = 0; i < 4; ++i){
            int newX = x + dx[i];
            int newY = y + dy[i];
            if (newX >= 0 && newX < xLength && newY >= 0 && newY < yLength && !isVisited[newX][newY] && word.charAt(depth + 1) == board[newX][newY]){
                deepFirstSearch(depth + 1, newX, newY, board, word);
                isVisited[newX][newY] = false;//回溯
            }

        }
        isVisited[x][y] = false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值