leetcode之回溯刷题总结2

leetcode之回溯刷题总结2

1-解数独
题目链接:题目链接戳这里!!!

思路:递归+回溯
首先预处理board数组,如果是数字,则使用row[i][digit]标记数字digit+1在第i行出现过,column[j][digit]表示数字digit+1在第j列出现过,block[i/3][j/3][digit]数字digit+1在3*3的方格内出现过,后面递归依次尝试所有数字,如果满足条件则放入,否则回溯到最初位置继续尝试。

class Solution {
    List<int[]> list = new ArrayList<>() ;
    boolean [][] row = new boolean [9][9] ;
    boolean [][] column = new boolean [9][9] ;
    boolean [][][] block = new boolean [3][3][9] ;
    boolean valid = false ;
    public void solveSudoku(char[][] board) {
        for(int i=0; i<9; i++){
            for(int j=0; j<9; j++){
                if(board[i][j]=='.'){
                    list.add(new int []{i,j}) ;
                }else{
                    int digit = board[i][j] - '0' - 1;
                    row[i][digit] = column[j][digit] = block[i/3][j/3][digit] = true ;
                }
            }
        }
        dfs(0,board) ;
    }
    public void dfs(int k, char [][] board){
        if(k==list.size()){
            valid = true ;
            return ;
        }
       int [] space = list.get(k) ;
       int i = space[0], j = space[1] ;
       for(int digit=0; digit<9 && !valid; digit++){
           if(!row[i][digit] && !column[j][digit] && !block[i/3][j/3][digit]){
               row[i][digit] = column[j][digit] = block[i/3][j/3][digit] = true ;
               board[i][j] = (char)(digit + '0' + 1) ;
               dfs(k+1, board) ;
               row[i][digit] = column[j][digit] = block[i/3][j/3][digit] = false ;
           }
       }
    }
}

在这里插入图片描述
2-N皇后
题目链接:题目链接戳这里!!!

思路:递归+回溯法
皇后的走法是:可以横直斜走,格数不限。因此要求皇后彼此之间不能相互攻击,等价于要求任何两个皇后都不能在同一行、同一列以及同一条斜线上。
回溯的具体做法是:使用一个数组记录每行放置的皇后的列下标,依次在每一行放置一个皇后。每次新放置的皇后都不能和已经放置的皇后之间有攻击:即新放置的皇后不能和任何一个已经放置的皇后在同一列以及同一条斜线上,并更新数组中的当前行的皇后列下标。当 N 个皇后都放置完毕,则找到一个可能的解。当找到一个可能的解之后,将数组转换成表示棋盘状态的列表,并将该棋盘状态的列表加入返回列表。

class Solution {
    List<List<String>> ans = new ArrayList<>() ;
    public List<List<String>> solveNQueens(int n) {
        Set<Integer> columns = new HashSet<>() ;
        Set<Integer> diagonals1 = new HashSet<>() ;
        Set<Integer> diagonals2 = new HashSet<>() ;
        int [] queues = new int [n] ;
        Arrays.fill(queues,-1) ;
        dfs(0,n,columns,diagonals1,diagonals2, queues) ;
        return ans ;
    }
    public void dfs(int row, int n, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2, int [] queues){
        if(row==n){
            List<String> board = f(queues,n) ;
            ans.add(new ArrayList<>(board)) ;
            return ;
        }
        for(int i=0; i<n; i++){
            if(columns.contains(i)){
                continue ;
            }
            int diagonal1 = row + i ;
            if(diagonals1.contains(diagonal1)){
                continue ;
            }
            int diagonal2 = row - i ;
            if(diagonals2.contains(diagonal2)){
                continue ;
            }
            queues[row] = i ;
            columns.add(i) ;
            diagonals1.add(diagonal1) ;
            diagonals2.add(diagonal2) ;
            dfs(row+1, n, columns, diagonals1, diagonals2,queues) ;
            queues[row] = -1  ;
            columns.remove(i) ;
            diagonals1.remove(diagonal1) ;
            diagonals2.remove(diagonal2) ;

        }
    }
    public List<String> f(int [] queues, int n){
        List<String> list = new ArrayList<>() ;
        for(int i=0; i<n; i++){
            char [] a = new char [n] ;
            Arrays.fill(a,'.') ;
            a[queues[i]] = 'Q' ;
            list.add(new String(a)) ;
        }
        return list ;
    }
}

在这里插入图片描述
3-N皇后II
题目链接:题目链接戳这里!!!

思路:递归+回溯
这题和上一题思路一样,每一次只需要返回满足条件的种类数量即可。

class Solution {
    public int totalNQueens(int n) {
        Set<Integer> columns = new HashSet<>() ;
        Set<Integer> diagonals1 = new HashSet<>() ;
        Set<Integer> diagonals2 = new HashSet<>() ;
        return dfs(0,n,columns,diagonals1,diagonals2) ;
    }
    public int dfs(int row, int n, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2){
        if(row==n){
            return 1 ;
        }else{
            int cnt = 0 ;
        for(int i=0; i<n; i++){
            if(columns.contains(i)){
                continue ;
            }
            int diagonal1 = row + i ;
            if(diagonals1.contains(diagonal1)){
                continue ;
            }
            int diagonal2 = row - i ;
            if(diagonals2.contains(diagonal2)){
                continue ;
            }
            columns.add(i) ;
            diagonals1.add(diagonal1) ;
            diagonals2.add(diagonal2) ;
            cnt += dfs(row+1,n,columns,diagonals1,diagonals2) ;
            columns.remove(i) ;
            diagonals1.remove(diagonal1) ;
            diagonals2.remove(diagonal2) ;
        } 
          return cnt ;
        }
      
    }
}

在这里插入图片描述
4-字母大小写全排列
题目链接:题目链接戳这里!!!

思路1:如果下一个字符 c 是字母,将当前已遍历过的字符串全排列复制两份,在第一份的每个字符串末尾添加 lowercase©,在第二份的每个字符串末尾添加 uppercase©。

class Solution {
    public List<String> letterCasePermutation(String s) {
        List<StringBuilder> res = new ArrayList<>() ;
        List<String> list = new ArrayList<>() ;
        res.add(new StringBuilder()) ;

        for(char c : s.toCharArray()){
            int n = res.size();
            if(Character.isLetter(c)){
            for(int i=0; i<n; i++){
                res.add(new StringBuilder(res.get(i))) ;
                res.get(i).append(Character.toUpperCase(c)) ;
                res.get(n+i).append(Character.toLowerCase(c)) ;
            }
            }else{
                for(int i=0; i<n; i++){
                    res.get(i).append(c) ;
                }
            }
        }
        for(StringBuilder ans : res){
            list.add(ans.toString()) ;
        }
        return list ;
    }
}

在这里插入图片描述
思路2:搜索+回溯
递归搜索,如果是数字,直接添加,字母则转换之后添加,同时,每一轮搜索完成,需要回溯到原始状态。

class Solution {
    List<String> res = new ArrayList<>() ;
    char [] c ;
    public List<String> letterCasePermutation(String s) {
      c = s.toCharArray() ;
      dfs(0,new StringBuilder()) ;
      return res ;
    }
    public void dfs(int idx, StringBuilder str){
        if(idx>=c.length){
            res.add(str.toString()) ;
            return ;
        }
        dfs(idx+1,str.append(c[idx])) ;
        str.deleteCharAt(idx) ;
     
        if(c[idx]>='a'){
            dfs(idx+1,str.append((char)(c[idx]-32))) ;
             str.deleteCharAt(idx) ;
        }else if(c[idx]>='A'){
            dfs(idx+1,str.append((char)(c[idx]+32))) ;
             str.deleteCharAt(idx) ;
        }
          
    }
}

在这里插入图片描述
思路3:递归法

class Solution {
    List<String> res = new ArrayList<>() ;
    public List<String> letterCasePermutation(String s) {
      char []c = s.toCharArray() ;
      dfs(0,c) ;
      return res ;
    }
    public void dfs(int idx, char [] c){
        if(idx>=c.length){
            res.add(new String(c)) ;
            return ;
        }
      
      char ch = c[idx] ;
       if(Character.isLetter(ch)){
           c[idx] = Character.toLowerCase(ch) ;
           dfs(idx+1,c) ;
           c[idx] = Character.toUpperCase(ch) ;
           dfs(idx+1,c) ;
       }else{
           dfs(idx+1,c) ;
       }
          
    }
}

在这里插入图片描述
5-单词搜索
题目链接:题目链接戳这里!!!

思路:搜索+回溯
压着四个方向搜索,每一次搜索标记,未被访问且没有越界,则可以继续搜索,每轮搜索完成需要标记数组需要回溯到原始状态。

class Solution {
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    boolean flags = false ;
    public boolean exist(char[][] board, String word) {
        boolean [][] vis = new boolean[board.length][board[0].length] ;
        for(int i=0;i<board.length; i++){
            for(int j=0; j<board[0].length; j++){
                boolean flag = dfs(board,i,j,vis,word,0) ;
                if(flag){
                    return true ;
                }
            }
        }
        return false ;
    }
    public boolean dfs(char [][]board, int x, int y, boolean [][] vis, String word,int begin){
        if(board[x][y]!=word.charAt(begin)){
            return false ;
        }
        if(begin==word.length()-1){
            return true ;
        }
        
        vis[x][y] = true ;
        for(int i=0; i<4; i++){
            int tx = x + dx[i] ;
            int ty = y + dy[i] ;
            if(tx<0 || ty<0 || tx>board.length-1 || ty>board[0].length-1){
                continue ;
            }
            if(!vis[tx][ty]){
            flags = dfs(board,tx,ty,vis,word,begin+1) ;
            if(flags){
                return true ;
            }
            }
        }
          vis[x][y] = false ;
        return flags ;
    }
}

在这里插入图片描述
6-黄金矿工
题目链接:题目链接戳这里!!!

思路:搜索+回溯
沿着四个方向搜索,当前值大于0则继续搜索,每次搜索要求和,同时标记为0,同时求出最大值,搜索完后后,要回溯到原始状态。

class Solution {
    int res = 0;
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    public int getMaximumGold(int[][] grid) {
        for(int i=0; i<grid.length; i++){
            for(int j=0; j<grid[0].length; j++){
                if(grid[i][j]>0){ 
                    dfs(grid,i,j,0) ;
                }
            }
        }
        return res ;
    }
    public void dfs(int [][] grid, int x, int y, int sum){
        if(x<0 || y<0 || x>grid.length-1 || y>grid[0].length-1){
                return ;
        }
       int temp = grid[x][y] ;
        sum += grid[x][y] ;
        grid[x][y] = 0 ;
        res = Math.max(res,sum) ;
        for(int i=0; i<4; i++){
            int tx = x + dx[i] ;
            int ty = y + dy[i] ;
            if(tx<0 || ty<0 || tx>grid.length-1 || ty>grid[0].length-1){
                continue ;
        }
            if(grid[tx][ty]>0){
                dfs(grid,tx,ty,sum) ;
            }
        }
        sum -= grid[x][y] ;
        grid[x][y] = temp ;
    }
}

在这里插入图片描述
7-活字印刷
题目链接:题目链接戳这里!!!

思路:递归+回溯+set集合去重

class Solution {
    public int numTilePossibilities(String tiles) {
        Set<String> res = new TreeSet<>() ;
        int n = tiles.length() ;
        boolean [] vis = new boolean [n]  ;
        dfs(res,tiles,vis,new StringBuilder()) ;
        return res.size()-1 ;
    }
    public void dfs(Set<String> res, String tiles, boolean [] vis, StringBuilder temp){
        res.add(temp.toString()) ;
        for(int i=0; i<tiles.length(); i++){
            if(!vis[i]){
                vis[i] = true ;
                temp.append(tiles.charAt(i)) ;
                dfs(res,tiles,vis,temp) ;
                temp.deleteCharAt(temp.length()-1) ;
                vis[i] = false ;
            }
        }
    }
}

在这里插入图片描述
这样写效率高一些。

class Solution {
    int cnt = 0 ;
    public int numTilePossibilities(String tiles) {
       char [] c = tiles.toCharArray() ;
       Arrays.sort(c) ;
       boolean [] vis = new boolean[c.length] ;
       for(int i=1; i<=tiles.length(); i++){
           dfs(c,vis,0,i) ;
       }
       return cnt ;
    }
    public void dfs(char [] c, boolean [] vis, int cur, int target){
        if(cur == target){
            cnt ++ ;
            return ;
        }
        for(int i=0; i<c.length; i++){
            if(vis[i]){
                continue ;
            }
            if(i>0 && c[i-1]==c[i] && !vis[i-1]){
                continue ;
            }
            vis[i] = true ;
            cur += 1 ;
            dfs(c,vis,cur,target) ;
            cur -= 1 ;
            vis[i] = false ;
        }
    } 
}

在这里插入图片描述

今天就止步到这里了,我要返校了,理工见!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuist__NJUPT

给个鼓励吧,谢谢你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值