回溯算法之深度优先搜索

目录

放牌

员工的重要性

图像渲染

岛屿的周长

被围绕的区域

岛屿的数量

岛屿的最大面积 

 电话号码的字母组合

二进制手表 

组合总和

活字印刷

N皇后



深度优先搜索(Depth First Search)------ 一条道走到黑

放牌

假如有编号为1~3的3张扑克牌和编号为1~3的3个盒子,现在需要将3张牌分别放到3个盒子中去,且每个盒子只能放一张牌,一共有多少种不同的放法。

步骤:

        1.边界,如果遍历到了最后一个,输出遍历结果

        2.遍历每一个牌

                1.如果没有使用过,放入牌,盒子标记为1

                2.进入下一个遍历

                3.回溯,取出最后一个放入的牌

public static void Dfs(int index, int n, int[] boxs, int[] book){
    if(index==n+1){//边界:最后一个-->此时牌都放入了,直接输出结果
        //输出这一次的遍历结果
        for (int i = 1; i <=n ; i++) {
            System.out.print(boxs[i]+" ");
        }
        //一次结果输出后,回车
            System.out.println();
            return;

    }
    for(int i=1;i<=n;i++){
        //判断当前牌是否用过
        if(book[i]==0){
            //没有使用过,放入牌,盒子标记为1
            boxs[index]=i;
            book[i]=1;//i号牌已经使用
            //处理下一个盒子
            Dfs(index+1,n,boxs,book);
            //从下一个盒子回退到当前盒子,取出当前盒子的牌
            book[i]=0;
        }
    }
}

public static void main(String[] args) {
    int n;
    Scanner sc = new Scanner(System.in);
    n = sc.nextInt();//盒子和牌个数
    int[] boxs = new int[n + 1];//盒子
    int[] books = new int[n + 1];//牌
    Dfs(1, n, boxs, books);
}

员工的重要性

回溯算法之深度优先搜索_第1张图片

class Solution {
    public int DFS(Map info, int id){
        //当前员工的import和他所有下属的import
        Employee curE=info.get(id);//得到id
        int sum=curE.importance;//通过id,得到import和
        for (int subId: curE.subordinates) {//遍历下属,得到总和
            sum+=DFS(info,subId);
        }
        return sum;
    }
    public int getImportance(List employees, int id) {
        if(employees.isEmpty()){
            return 0;
        }
        Map info=new HashMap<>();
        //信息放入info中
        for(Employee e:employees){
            info.put(e.id,e);//从list中取出list中的元素,放入info中
        }
        //遍历总和
        return DFS(info,id);

    }
}

图像渲染

回溯算法之深度优先搜索_第2张图片

 步骤:

floodFill

        1.得到矩阵的长宽,指定位置原本的颜色

        2.创建数组book,判断该位置是否遍历过        

        3.进入dfs

        4.输出结果image

dfs

        1.把当前位置颜色改变,标记为遍历过

        2.遍历四个方向

        3.得到新的位置

        4.判断位置是否合法

        5.判断是否和原颜色相同,是否标记过

        5.满足要求,进行递归

class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int color) {
        int oldcolor=image[sr][sc];
        int row=image.length;
        int col=image[0].length;
        int[][] book=new int[row][col];
        dfs(image,sr,sc,book,row,col,oldcolor,color);
        return image;
    }
    int[][] next={{1,0},{-1,0},{0,1},{0,-1}};
    public void dfs(int[][] image,int curx,int cury,int[][] book,int row,int col,int oldcolor,int color){
        image[curx][cury]=color;
        book[curx][cury]=1;
        for(int i=0;i<4;i++){
            int newx=curx+next[i][0];
            int newy=cury+next[i][1];

            if(newx>=row || newx<0 || newy>=col || newy<0){
                continue;
            }
            if(image[newx][newy]==oldcolor && book[newx][newy]==0){
                dfs(image,newx,newy,book,row,col,oldcolor,color);
            }
        }
    }

   
}

岛屿的周长

回溯算法之深度优先搜索_第3张图片

 遍历,判断是不是陆地,如果是进入dfs

  • 判断位置是否合法
  • 判断是否是水域,返回1
  • 判断不是陆地或标记过,返回0
  • 进入四个方向遍历
class Solution {
     public int islandPerimeter(int[][] grid) {
         for(int i=0;i=grid.length || j<0 || j>=grid[0].length){
            return 1;
        }
        //水域+1
        if(grid[i][j]==0){
            return 1;
        }
        //遍历过 在内部,周长不增加
        if(grid[i][j]!=1){
            return 0;
        }
        //遍历过,防止再次遍历
        grid[i][j]=2;
        return dfs(grid,i-1,j)+dfs(grid,i+1,j)+dfs(grid,i,j+1)+dfs(grid,i,j-1);
    }
}

被围绕的区域

回溯算法之深度优先搜索_第4张图片

 从四个边遍历,把边上的O变为A,把剩下的O(此时的O都是被包围的)变为X,把A变为O

步骤:

  • solve
    • 找到第一行,第一列,最后一行,最后一列,进入dfs,直到不为O
  • dfs
    • 标记当前位置
    • 遍历四个方向
    • 得到新的坐标]
    • 判断坐标是否合法
    • 如果是O,并且没有标记过,进入下一个
class Solution {
   
    public void solve(char[][] board) {
        if(board==null){
            return ;
        }
     int row=board.length;
     int col=board[0].length;
     int[][] book=new int[row][col];
     for(int i=0;i=row || ny<0 || ny>=col){
                continue;
            }

            if(board[nx][ny]=='O'){
                dfs(board,nx,ny,row,col,book);
            }
        }
    }
}

岛屿的数量

回溯算法之深度优先搜索_第5张图片

步骤

  •  遍历矩阵,如果是陆地没有遍历过
  • ret++,进入dfs
  • dfs
    • 标记当前位置
    • 遍历四个方向
    • 得到新的坐标
    • 判断坐标是否合法
    • 如果是陆地没有遍历过
    • 进入下一个判断

class Solution {
    public int numIslands(char[][] grid) {
        int ret=0;
         int row=grid.length;
         int col=grid[0].length;
         int[][] book=new int[row][col];
         for(int i=0;i=row || nx<0 || ny>=col || ny<0){
                   continue;
               }

               if(grid[nx][ny]=='1' && book[nx][ny]==0){
                   dfs(grid,book,row,col,nx,ny);
               }
           }
       }
}

岛屿的最大面积 

回溯算法之深度优先搜索_第6张图片

步骤

  •  遍历数组,找到是陆地并且没有标记过的进入dfs
  • dfs
    • 把当前位置标记
    • 遍历四个方向
    • 得到新的坐标
    • 判断坐标是否合法
    • 判断是否是陆地,是否遍历过-->进入递归,得到和
    • 返回和
  • 得到每一次和的最大值,返回
class Solution {
      public int maxAreaOfIsland(int[][] grid) {
        if(grid.length==0){
            return 0;
        }
        int row=grid.length;
        int col=grid[0].length;
        int[][] book=new int[row][col];
        int max=0;
        int ret=0;
        for(int i=0;i=row || nx<0 || ny>=col || ny<0){
                continue;
            }

            if(grid[nx][ny]==1 && book[nx][ny]==0){
                r+=dfs(grid,book,row,col,nx,ny);
            }
        }
        return r;
        
    }
}

 电话号码的字母组合

回溯算法之深度优先搜索_第7张图片

步骤 

  • 把信息存放到字符串数组中,下标对应得到的数字
  • 边界:当前位置下标和字符串长度相等(遍历完),把字符串放入list中
  • 找到对应位置:通过当前下标,得到对应下标的数字,通过数字得到字符串数组中对应的字符串
  • 遍历字符串,进行下一个新的判断
public List letterCombinations(String digits) {
    List ret=new ArrayList<>();
    StringBuilder curStr=new StringBuilder("");
    dfs(digits,ret,curStr,0);
    //  数组 结果存放 当前字符串    遍历的长度
    return ret;

}

String[] mapString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
private void dfs(String digits, List ret, StringBuilder curStr, int curDepth) {
   //边界
    if(curDepth==digits.length()){
        if(curStr.length()!=0){
            ret.add(curStr.toString());
        }
        return;
    }
    //找到对应位置
    int curMapIndex=digits.charAt(curDepth)-'0';//得到当前的数字
    String curMap=mapString[curMapIndex];//通过数字找到该下标的所有字母
    for (int i = 0; i < curMap.length(); i++) {
        //当前字符串加入新的字母(得到的字符串的每个元素依次遍历)
        dfs(digits, ret, curStr.append(curMap.charAt(i)), curDepth+1);
        //结束后,去掉新加的字母,为下一个字母的加入做准备
        curStr.deleteCharAt(curStr.length()-1);
    }
}

二进制手表 

回溯算法之深度优先搜索_第8张图片

步骤:

        1. 判断边界  h>11 m>59  不满足

        2.如果在边界上,还需要的灯的个数为0   时间放入list中

        3.把十个灯遍历,得到对应的时间  

class Solution {
    int[] hs={1,2,4,8,0,0,0,0,0,0};
    int[] ms={0,0,0,0,1,2,4,8,16,32};
    List list=new ArrayList<>();
    public List readBinaryWatch(int turnedOn) {
             dfs(turnedOn,0,0,0);
             return list;
    }
    public void dfs(int turnedOn,int index,int h,int m){
        if(h>11 || m>59){
            return ;
        }
        if(turnedOn==0){
            list.add(h+":"+(m<10?"0":"")+m);
        }
        for(int i=index;i<10;i++){
            dfs(turnedOn-1,i+1,h+hs[i],m+ms[i]);
        }
    }
}

组合总和

回溯算法之深度优先搜索_第9张图片

 dfs:

等于目标返回

从当前位置到最后一个位置,遍历

如果当前位置的值大于目标值,continue

深度搜索

去掉最后一个元素

class Solution {
    public List> combinationSum(int[] candidates, int target) {
       List> solutions=new ArrayList<>();
       List solution=new ArrayList<>();
       if(candidates.length==0){
           return solutions;
       }
       int curSum=0;
       dfs(solutions,solution,candidates,target,curSum,0);
       return solutions;
    }
    public static void dfs(List> solutions,List solution,int[] candidates,int target,int curSum,int index){
        if(curSum>=target){
            if(curSum==target){
                List newS=new ArrayList<>();
                for(int e:solution){
                    newS.add(e);
                }
                solutions.add(newS);
            }
            return;
        }
        for(int i=index;itarget){
                continue;
            }
            solution.add(candidates[i]);
            dfs(solutions,solution,candidates,target,curSum+candidates[i],i);
            solution.remove(solution.size()-1);
        }

    }
    
}

活字印刷

回溯算法之深度优先搜索_第10张图片

因为每个只能使用一次,所有要标记是否使用过,如果没有使用过标记为0,进入遍历

 dfs:

如果curStr长度不为0,放入set中

从0开始遍历titles

如果没有遍历过,标记为遍历,进入dfs,去到新加的,标记为没有遍历过

class Solution {
   public int numTilePossibilities(String tiles) {
        if(tiles.length()==0){
            return 0;
        }
        int[] book=new int[tiles.length()];
        Set total=new HashSet<>();
        StringBuilder curStr=new StringBuilder();
        dfs(tiles,curStr,book,total);
        return total.size();
    }

    private void dfs(String tiles, StringBuilder curStr, int[] book, Set total) {
        if(curStr.length()!=0){
            total.add(curStr.toString());
        }
        for(int i=0;i

N皇后

回溯算法之深度优先搜索_第11张图片

dfs:

  1. 判断是否遍历完,如果完成把结果存入solutions中
  2. 遍历
    1. 判断是否冲突,不冲突,继续
    2. 把当前元素的位置存入solution中
    3. 进入下一个判断
    4. 回溯 去掉新加的元素

isVaild:判断列,行列和,行列差知否冲突,

transResult:

  1. 遍历每一种方案
  2. 创建一个List> ret
  3. 把每一个都设置为.
  4. 通过solution把对应位置设置为Q
  5. 存入ret中
class pair{
    int x;
    int y;
    public pair(int x,int y){
        this.x=x;
        this.y=y;
    }
}
public class Solution {
    public List> solveNQueens(int n) {
       List> solutions=new ArrayList<>();
       List solution=new ArrayList();
       dfs(solutions,solution,0,n);
       return transResult(solutions,n);
    }

    private List> transResult(List> solutions, int n) {
         //遍历每一个方案
        List tmp=new ArrayList<>();
        //把每一种方案转换成string形式
        List> ret=new ArrayList<>();
        for(List solution:solutions){
            List solutionString=new ArrayList<>();

            for(int i=0;i curRet=new ArrayList<>();
                for(StringBuilder s:solutionString){
                    curRet.add(s.toString());
                }
                ret.add(curRet);
            }
            return ret;
        }



    public void dfs(List> solutions,
                    List solution, int curRow, int n){
       if(curRow==n){
           List newS=new ArrayList<>();
           for(pair p:solution){
               newS.add(p);
           }
           solutions.add(newS);
       }

       for(int i=0;i solution, int row, int col) {
       for(pair i:solution){
           if(i.y==col || i.x+i.y==row+col || i.x-i.y==row-col){
               return false;
           }
       }
       return true;
    }
}

你可能感兴趣的:(算法,深度优先)