leetcode之回溯刷题总结2

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 以上是关于leetcode之回溯刷题总结2的主要内容,如果未能解决你的问题,请参考以下文章

leetcode之回溯刷题总结3

leetcode刷题之回溯法

leetcode之并查集+记忆化搜索+回溯+最小生成树刷题总结1

Leetcode之深度遍历递归与回溯法汇总

leetcode之贪心算法刷题总结2

leetcode之模拟刷题总结2