【代码训练营】day30 | 332.重新安排行程 & 51. N皇后 & 37. 解数独

所用代码 java

重新安排行程 LeetCode 332

题目链接:重新安排行程 LeetCode 332 - 困难

思路

无。题都看不懂


class Solution {
    Deque<String> res;
    // 存放 起点机场 -> 终点机场,航班次数
    Map<String, Map<String, Integer>> map;
    public List<String> findItinerary(List<List<String>> tickets) {
        res = new LinkedList<>();
        map = new HashMap<>();
        for (List<String> t : tickets){
            Map<String, Integer> temp;
            // 如果航班的出发点已存在
            if (map.containsKey(t.get(0))){
                // 先把该机场的终点赋值为temp
                temp = map.get(t.get(0));
                // 把另一航班赋值给temp
                // 没有就把value赋值为 1,有就加 1,记录多少趟航班,以免出现重复
                temp.put(t.get(1), temp.getOrDefault(t.get(1), 0) + 1);
            }else {
                // 没有该目的地的信息,就新建一个treemap来存目的地,treemap的key自动按升序排序
                temp = new TreeMap<>();
                temp.put(t.get(1), 1);
            }
            // 最后把起点和终点保存到一个map里面去
            map.put(t.get(0), temp);
        }// 此时map里面就存了所有机场的起点=>终点的信息,以及航班的趟数
        res.add("JFK"); // 起点机场一是 JFK
        backtracking(tickets.size());
        return new ArrayList<>(res);
    }// 只需要传入多少趟行程,因为返回的结果正好等于行程数+1,就可覆盖完所有航程
    // 即n条航线有n+1个点
    public boolean backtracking(int ticketNum){
        // 终止条件
        if (res.size() == ticketNum + 1){
            return true;
        }// 每次都是从末尾开始一个一个添加
        String last = res.getLast();
        // 第一个从 JFK 开始出发
        if (map.containsKey(last)){
            for (Map.Entry<String, Integer> target : map.get(last).entrySet()){
                // 记录到该机场的躺数还有没有
                int count = target.getValue();
                if (count > 0){
                    // 有就加进去
                    res.add(target.getKey());
                    target.setValue(count-1);
                    boolean result = backtracking(ticketNum);
                    // 如果每次都添加进去了,当满足终止条件后就返回的true,并一直往上返回true
                    if (result) return true;
                    // 回溯操作
                    res.removeLast();
                    // 前面并没有修改count的值,所以回溯是不能count+1
                    target.setValue(count);
                }
            }
        }
        // 最后返回false是该机场没有下一目的地,而我们的航程还没遍历完
        return false;
    }
}

总结

太难了~~

N皇后 LeetCode 51

题目链接:N皇后 LeetCode 51 - 困难

思路

无。


class Solution {
    List<List<String>> res = new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
        char[][] chessboard = new char[n][n];
        for (char[] c : chessboard) {
            Arrays.fill(c, '.');
        }
        backtracking(chessboard, 0, n);
        return res;
    }// row 表示行(递归宽度),n表示列(递归深度) 也表示棋盘的大小
    public void backtracking(char[][] chessboard, int row, int n){
        if (n == row){
            res.add(getList(chessboard));
            return;
        }for (int col = 0; col < n; col++) {
            // col 表示每层遍历的列的位置
            // n 在这里表示棋盘的大小
            if (isValid(chessboard, row, col, n)){
                chessboard[row][col] = 'Q';
                // 每层递归从第二行开始 row+1
                backtracking(chessboard, row+1, n);
                chessboard[row][col] = '.'; // 回溯
            }
        }
        return;
    }// 只用判断 上方,左斜45°,右斜45°
    // 同一行由上边for循环控制
    public boolean isValid(char[][] chessboard, int row, int col, int n){
        // 检查上方是否有皇后
        for (int i = 0; i < row; i++) {
            // 第 i 行,col列存在,返回false
            if (chessboard[i][col] == 'Q'){
                return false;
            }
        }// 检查左斜上45°是否有皇后
        // 从row行,col列的  左上第一个位置开始判断
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (chessboard[i][j] == 'Q'){
                return false;
            }
        }// 检查右斜上45°是否有皇后
        // 从row行,col列的  右上第一个位置开始判断
        for (int i = row - 1, j = col + 1 ; i >= 0 && j < n; i--, j++) {
            if (chessboard[i][j] == 'Q'){
                return false;
            }
        }// 可以放皇后
        return true;
    }public List<String> getList(char[][] chessboard){
        List<String> list = new ArrayList<>();
        for (char[] c : chessboard) {
            list.add(String.copyValueOf(c));
        }
        return list;
    }
}

总结

本题为经典回溯题,难度有点大,若学会了便可对回溯有更深层的理解。

解数独 LeetCode 37

题目链接:解数独 LeetCode 37 - 困难

思路

无。


n皇后是一个for循环遍历一行,一个递归遍历一列,且每一行只需要填一个数。

本题是需要填一行的所有数,所以需要两个for循环,一个遍历行,一个遍历列,最后递归进行判断放某个数字可否行

class Solution {
    public void solveSudoku(char[][] board) {
        backtracking(board);
    }// board : 9 x 9
    public boolean backtracking(char[][] board){
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                // 在board[i][j]的情况下判断是否可以放下数字
                if (board[i][j] == '.'){
                    for (char k = '1'; k <= '9'; k++) {
                        // 棋盘在i行j列的位置可以放下k
                        if (isValid(board, i, j, k)){
                            board[i][j] = k;
                            boolean result = backtracking(board);
                            // 如果每次放的数都合理就一直往下放,然后把棋盘放满
                            // 放满棋盘之后,下面就这步就一直向上返回true,直到最后回到第一步
                            if (result) return true;
                            board[i][j] = '.';
                        }
                    }
                    // 棋盘该位置所有数字都没法放,就返回false
                    return false;
                }
                
            }
        }
        // 如果所有棋盘都填满了,就返回ture
        return true;
    }// 判断棋盘board在i行j列能否放数字k
    // 3x3的棋盘是否都出现过所有数字
    public boolean isValid(char[][] board, int i, int j, char k){
        // 判断第 i 行是否合理 -- i行的每一列
        for (int col = 0; col < board.length; col++) {
            if (board[i][col] == k) return false;
        }
        // j 列是否合理 -- j列的每一个行
        for (int row = 0; row < board[j].length; row++) {
            if (board[row][j] == k) return false;
        }
        // 判断3x3棋盘是否合理
        // 把行和列放在每3x3小格的第一个数
        int startRow = (i / 3) * 3;
        int startCol = (j / 3) * 3;
        // 每次只需要判断从这个数字开始往后往下数3行就行了
        for (int m = startRow; m < startRow + 3; m++) {
            for (int n = startCol; n < startCol + 3; n++) {
                if (board[m][n] == k) return false;
            }
        }
        return true;
    }
}

总结

本题返回值之所以是布尔类型,原因是本题我们只需要返回一个结果就行,搜索到正确的结果就直接返回。而之前的题返回值是void,是因为我们要搜索所有的结果,并保存每一个结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值