Leetcode之查找(二)

目录

9.set-matrix-zeroes

10.generate-parentheses

11.letter-combinations-of-a-phone-number

12.valid-sudoku

13.sudoku-solver


9.set-matrix-zeroes

题目:给定一个m*n的矩阵,如果有一个元素是0,就把该元素所在的行和列上的元素全置为0,要求使用原地算法。

分析:最简单的方法是分别用两个list存储元素为0的行和列,再遍历矩阵,如果该元素的行或者列在list中,就把其置为0,但这种方法需要额外的存储空间,而题意要求用原地算法,所以我们需采用另一种方法。我们可以用每行和每列的第一个元素作为标记,这个标记用来表示这一行或者这一列是否需要赋零。首先遍历整个矩阵,如果 matrix[i][j] == 0 就将第 i 行和第 j 列的第一个元素标记,但是由于第一行和第一列的标记都是 cell[0][0],所以需要一个额外的变量标记第一列是否需置为零,同时用 cell[0][0] 继续表示第一行的标记。

    public void setZeroes(int[][] matrix) {
        int row = matrix.length;
        if(row == 0)
            return;
        boolean flag = false;//用于标记第一列是否要设置为0
        int col = matrix[0].length;
        for(int i = 0;i < row;i++){
            if(matrix[i][0] == 0)
                flag = true;
            for(int j = 1;j < col;j++){
                if(matrix[i][j] == 0){//标记第i行和第j列的第一个元素为0
                    matrix[i][0] = 0;matrix[0][j] = 0;
                }
            }
        }
        for(int i = 1;i < row;i++) {
            for (int j = 1; j < col; j++) {
                if(matrix[i][0] == 0 || matrix[0][j] == 0)
                    matrix[i][j] = 0;
            }
        }
        if(matrix[0][0] == 0){//第一行是否需要设置为0
            for(int i = 1;i < col;i++)
                matrix[0][i] = 0;
        }
        if(flag){//第一列是否需要设置为0
            for(int i = 0;i < row;i++)
                matrix[i][0] = 0;
        }
    }

10.generate-parentheses

题目:给出n对括号,请编写一个函数来生成所有的由n对括号组成的合法组合。例如,给出n=3,解集为:"((()))", "(()())", "(())()", "()(())", "()()()"

分析:回溯法。添加括号只有左括号和右括号两种选择,我们可以通过跟踪到目前为止放置的左括号和右括号的数目来保证序列的有效性,如果左括号数量小于n,可以放一个左括号;如果右括号数量小于左括号的数量,可以放一个右括号;而当右括号数量等于n时就得到了一个有效序列。

    public List<String> generateParenthesis(int n) {
        List<String> result = new ArrayList<>();
        if(n == 0)
            return result;
       f(0,0,n,"",result);
        return result;
    }

    private void f(int left, int right, int n,String cur, List<String> result) {
        if(right == n){
            result.add(cur);
            return;
        }
        if(left < n)
            f(left + 1,right,n,cur + "(",result);
        if(right < left)
            f(left,right+1,n,cur + ")",result);
    }

11.letter-combinations-of-a-phone-number

题目:给出一个仅包含数字的字符串,给出所有可能的字母组合。数字到字母的映射方式如下:(就像电话上数字和字母的映射一样)。Input:Digit string "23"Output:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].注意:虽然上述答案是按字典序排列的,但你的答案可以按任意的顺序给出。

分析:回溯法。先将对应的映射存入到map中或者String数组中,然后对于每个数字依次放入其中一个字母,通过回溯穷举即可。

    String[] map = {" ","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    public List<String> letterCombinations(String digits) {
        List<String> result = new ArrayList<>();
        if(digits.length() == 0)
            return result;
        f(result,digits,new StringBuilder(),0);
        return result;
    }

    private void f(List<String> result, String digits,StringBuilder cur, int index) {
        if(index == digits.length()){
            result.add(cur.toString());
            return;
        }
        String s = map[digits.charAt(index) - '0'];
        for(int i = 0;i < s.length();i++){
            cur.append(s.charAt(i));
            f(result,digits,cur,index + 1);
            cur.deleteCharAt(cur.length() - 1);
        }
    }

12.valid-sudoku

题目:判断一个 9x9 的数独是否有效。数独:数字 1-9 在每一行只能出现一次;数字 1-9 在每一列只能出现一次;数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

分析:按照从左往右、从上往下的顺序遍历一次board,只通过一次遍历来判断每一行、每一列、每个九宫格是否有相同的数字。因为board中的整数限定在1到9的范围内,因此可以分别建立哈希表(这里采用二维数组)来存储1-9在在行、列、九宫格上出现的次数。注意第i行第j列的数字在第(row / 3) * 3 + col / 3个子数独。

   public boolean isValidSudoku(char[][] board) {
        int[][] row = new int[9][10];//第i行j的数量个数
        int[][] col = new int[9][10];
        int[][] cube = new int[9][10];
        for(int i = 0;i < 9;i++){
            for(int j = 0;j < 9;j++){
                if(board[i][j] == '.')
                    continue;
                int cur = board[i][j] - '0',box = i / 3 * 3 + j / 3;
                if(row[i][cur] == 1 || col[j][cur] == 1 || cube[box][cur] == 1)
                    return false;
                row[i][cur] = 1;
                col[j][cur] = 1;
                cube[box][cur] = 1;
            }
        }
        return true;
  }

13.sudoku-solver

题目:请编写一个程序,给数独中的剩余的空格填写上数字,空格用字符'.'表示,假设给定的数独只有唯一的解法

分析:最简单的方法是暴力法,对每个空格判断写入1-9是否符合数独,符合则试着填入。这里采用另一种优化的方法,跟上题类似,建立哈希表(这里采用二维数组)来存储1-9在在行、列、九宫格上是否出现,确定可用才填入,如果填充失败就进行回溯。

   public void solveSudoku(char[][] board) {
        boolean[][] row = new boolean[9][10];//第i行中j是否出现
        boolean[][] col = new boolean[9][10];
        boolean[][] cube = new boolean[9][10];
        //初始化
        for(int i = 0;i < 9;i++)
            for(int j = 0;j < 9;j++)
                if(board[i][j] != '.'){
                    int num = board[i][j] - '0';
                    row[i][num] = true;col[j][num] = true;
                    cube[i/3*3+j/3][num] = true;
                }
        solveSudokuCore(board,row,col,cube,0);
    }

    private boolean solveSudokuCore(char[][] board, boolean[][] row, boolean[][] col, boolean[][] cube, int count) {
        if(count == 81)
            return true;
        int r = count / 9,c = count % 9;
        if(board[r][c] != '.')
            return solveSudokuCore(board,row,col,cube,count + 1);
        for(int i = 1;i <= 9;i++){//依次看1-9是否能填入
            int box = r / 3 * 3 + c / 3;
            if(!row[r][i] && !col[c][i] && !cube[box][i]){
                board[r][c] = (char)('0' + i);//试探
                row[r][i] = true;col[c][i] = true;cube[box][i] = true;
                if(solveSudokuCore(board,row,col,cube,count + 1))
                    return true;
                board[r][c] = '.';//回溯
                row[r][i] = false;col[c][i] = false;cube[box][i] = false;
            }
        }
        return false;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章