算法训练营第三十天|332.重新安排行程、51. N皇后、37. 解数独

62 阅读1分钟

332. 重新安排行程

class Solution {
    LinkedList<String> res = new LinkedList<>();
    LinkedList<String> path = new LinkedList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
        Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
        path.add("JFK");
        boolean[] used = new boolean[tickets.size()];
        backtrack((ArrayList) tickets, used);
        return res;
    }
    private boolean backtrack(ArrayList<List<String>> tickets, boolean[] used){
        if(path.size() == tickets.size() + 1){
            res = new LinkedList(path);
            return true;
        }

        for(int i = 0; i < tickets.size(); i++){
            if(!used[i] && tickets.get(i).get(0).equals(path.getLast())){
                path.add(tickets.get(i).get(1));
                used[i] = true;

                if(backtrack(tickets, used))return true;

                used[i] = false;
                path.removeLast();
            }
        }
        return false;
    }
}

51. N 皇后

class Solution {
    List<List<String>> res = new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
        // '.'表示空,'Q'表示皇后,初始化空棋盘
        List<String> board = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < n; i++){
            sb.append('.');
        }
        for(int i = 0; i < n; i++){
            board.add(sb.toString());
        }
        backtrack(board, 0);
        return res;
    }

    /**
     * *路径:board 中小于 row 的那些行都已经成功放置了皇后
     * *选择列表:第 row 行的所有列都是放置皇后的选择
     * *结束条件:row 超过 board 的最后一行
     */
    private void backtrack(List<String> board, int row){
        if(row == board.size()){
            res.add(new ArrayList<>(board));
            return;
        }

        int n = board.get(row).length();
        for(int col = 0; col < n; col++){
            // 排除不合法选项
            if(!isValid(board, row, col))continue;

            // 回溯模板
            char[] arr = board.get(row).toCharArray();
            arr[col] = 'Q';
            board.set(row, String.valueOf(arr));

            backtrack(board, row + 1);

            arr[col] = '.';
            board.set(row, String.valueOf(arr));
        }
    }

    // 是否可以在board[row][col]上放置皇后
    private boolean isValid(List<String> board, int row, int col){
        int n = board.size();

        // 检查列是否有皇后互相冲突
        for(int i = 0; i < n; i++){
            if(board.get(i).charAt(col) == 'Q')return false;
        }

        // 检查45度角是否有皇后互相冲突
        for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++){
            if(board.get(i).charAt(j) == 'Q')return false;
        }

        // 检查135度角是否有皇后互相冲突
        for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--){
            if(board.get(i).charAt(j) == 'Q')return false;
        }

        return true;
    }
}

37. 解数独

class Solution {
    public void solveSudoku(char[][] board) {
        backtrack(board);
    }
    private boolean backtrack(char[][] board){
        for(int i = 0; i < board.length; i++){ // 遍历行
            for(int j = 0; j < board[0].length; j++){ // 遍历列
                if(board[i][j] == '.'){
                    for(char k = '1'; k <= '9'; k++){ // (i,j)这个位置放k是否合适
                        if(isValid(i, j, k, board)){
                            // 回溯模板
                            board[i][j] = k;
                            if(backtrack(board))return true; // 如果找到一组合适的立即返回
                            board[i][j] = '.';
                        }
                    }
                    return false; // 9个数都试完了,都不行,就返回false
                }
            }
        }
        return true; // 遍历完了都没有返回false,说明走到了数独右下角,找到了合适棋盘位置
    }
    private boolean isValid(int row, int col, char val, char[][] board){
        for(int j = 0; j < 9; j++){ // 判断行里是否重复
            if(board[row][j] == val)return false;
        }
        for(int i = 0; i < 9; i++){ // 判断列里是否重复
            if(board[i][col] == val)return false;
        }

        // 判断九宫格里是否重复
        // 先除3,向下取整,得到(row, col)所在格子的大方格的行列起点,再遍历
        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;
    }
}