【代码随想录Day30】回溯算法

332 重新安排行程

https://leetcode.cn/problems/reconstruct-itinerary/

graph 用 Map<from, group of to> 表示,其中 group of to需要既能排序,又能mark机票是不是还能用,于是用treemap<to, 几张>表示。如果不用Map表示顶点,也可以直接用tickets表示edges来表示图,要找衔接航班时每次扫描一遍。

class Solution {         // 用 treemap<destination, usedOrNot> 不行,因为有重复机票
    public List<String> findItinerary(List<List<String>> tickets) {
        Map<String, TreeMap<String, Integer>> graph = new HashMap<>();
        for (List<String> ticket : tickets) {
            TreeMap<String, Integer> to = graph.getOrDefault(ticket.get(0), new TreeMap<>((a, b) -> a.compareTo(b)));
            to.put(ticket.get(1), to.getOrDefault(ticket.get(1), 0) + 1);
            graph.put(ticket.get(0), to);
        }
        List<String> result = new ArrayList<>();
        result.add("JFK");
        dfs(result, graph, tickets.size() + 1);
        return result;
    }
    private boolean dfs(List<String> result, Map<String, TreeMap<String, Integer>> graph, int n) {
        if (result.size() == n) {
            return true;
        }
        TreeMap<String, Integer> to = graph.get(result.get(result.size() - 1));
        if (to == null) return false;
        for (Map.Entry<String, Integer> ticket : to.entrySet()){
            if (ticket.getValue() == 0) continue;
            String des = ticket.getKey();
            to.put(des, ticket.getValue() - 1);
            result.add(des);
            if(dfs(result, graph, n)) return true;         //从叶子提前返回
            to.put(des, ticket.getValue() + 1);
            result.remove(result.size() - 1);
        }
        return false;
    }
}
/*class Solution {
    private LinkedList<String> res;
    private 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)));       //destination按字母序
        path.add("JFK");
        boolean[] used = new boolean[tickets.size()];
        backTracking((ArrayList) tickets, used);
        return res;
    }

    public boolean backTracking(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 (backTracking(tickets, used)) {
                    return true;
                }

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

51 N皇后

https://leetcode.cn/problems/n-queens/description/

class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> result = new ArrayList<>();
        char[] oneRow = new char[n];
        int[] positions = new int[n];
        Arrays.fill(oneRow, '.');
        dfs(result, oneRow, positions, 0);        //如果第i行的选择不是显性写在参数里,那么它就藏在list of current selection里,如list的长度
        return result;
    }
    private void dfs(List<List<String>> result, char[] oneRow, int[] positions, int i) {
        if (i == positions.length) {
            List<String> solution = new ArrayList<>();
            for (int j = 0; j < i; j++) {           //总共j行,每行上把positions[j]位置的char改为Q
                oneRow[positions[j]] = 'Q';          
                solution.add(new String(oneRow));
                oneRow[positions[j]] = '.';          //复原成一行....空置
            }
            result.add(solution); 
            return;
        }
        for (int j = 0; j < positions.length; j++) {
            if (validate(positions, i, j)) {
                positions[i] = j;                //成功在 i 行上放一个列为 j的皇后
                dfs(result, oneRow, positions, i + 1);
            }
        }
    }
    private boolean validate(int[] positions, int i, int j) {
        for (int k = 0; k < i; k++) {
            if (positions[k] == j || k + positions[k] == i + j || i - k == Math.abs(positions[k] - j)) return false;
        }
        return true;
    }
}

37 解数独

https://leetcode.cn/problems/sudoku-solver/description/ 这题到了base case如何返回比较难懂。第一种解法每层决定一个格子一共81层结束。第二种解法最后一层扫完81格没有点剩下返回true,中间层找到点试着放数,一个可行会返回true, 放9个都不行返回false.

class Solution {
    public void solveSudoku(char[][] board) {
        boolean[][] col = new boolean[9][9], row = new boolean[9][9], cell = new boolean[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') continue;
                int num = board[i][j] - '1';
                col[num][j] = true;
                row[num][i] = true;
                cell[num][(i / 3) * 3 + j / 3] = true;
            }
        }
        dfs(0, 0, board, col, row, cell);
    }
    private boolean dfs(int i, int j, char[][] board, boolean[][] col, boolean[][] row, boolean[][] cell) {
        if (j == 9) {
            j = 0; 
            i++;
        };
        if (i == 9) return true;
        if (board[i][j] != '.') return dfs(i, j + 1, board, col, row, cell);
        for (int num = 0; num < 9; num++) {
            if (col[num][j] || row[num][i] || cell[num][(i /3) * 3 + j / 3]) continue;
            board[i][j] = (char)(num + '1');                                             //bug (char)
            col[num][j] = row[num][i] = cell[num][(i /3) * 3 + j / 3] = true;
            if (dfs(i, j + 1, board, col, row, cell)) return true;
            board[i][j] = '.';
            col[num][j] = row[num][i] = cell[num][(i /3) * 3 + j / 3] = false;
        }
        return false;
    }
}
class Solution {      
    public void solveSudoku(char[][] board) {
        boolean[][] rowUsed = new boolean[9][9];
        boolean[][] colUsed = new boolean[9][9];
        boolean[][] sqrUsed = new boolean[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] != '.') {
                    int num = board[i][j] - '1';
                    rowUsed[i][num] = true;
                    colUsed[j][num] = true;
                    sqrUsed[i / 3 * 3 + j / 3][num] = true;
                }
            }
        }
        dfs(board, rowUsed, colUsed, sqrUsed, count, 0);
    }
    private boolean dfs(char[][] board, boolean[][] rowUsed, boolean[][] colUsed, boolean[][] sqrUsed, int count, int start) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (i * 9 + j < start || board[i][j] != '.') continue;   
                for (int k = 0; k < 9; k++) {
                    if (rowUsed[i][k] || colUsed[j][k] || sqrUsed[i / 3 * 3 +j / 3][k]) continue;
                    rowUsed[i][k] = true;
                    colUsed[j][k] = true;
                    sqrUsed[i / 3 * 3 +j / 3][k] = true;
                    board[i][j] = (char)('1' + k);
                    if (dfs(board, rowUsed, colUsed, sqrUsed, i * 9 + j + 1)) return true;
                    rowUsed[i][k] = false;
                    colUsed[j][k] = false;
                    sqrUsed[i / 3 * 3 +j / 3][k] = false;
                    board[i][j] = '.';
                }
                return false;  //如果9个数都试玩了还不行,那么返回false
            }
        }
        return true;  //如果棋盘全部遍历完没有返回false那么就排好了
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值