Day 28算法记录|回溯

总结

我的总结:
参考了:

323.重新安排行程

利用HashMap和LinkedList,这个

map:键保存起始地,值装一个优先队列

class Solution {
    Map<String, PriorityQueue<String>> map = new HashMap<>();
    LinkedList<String> res = new LinkedList<>();
    public List<String> findItinerary(List<List<String>> tickets) {
    
    for(List<String> ticket : tickets){
        String src = ticket.get(0);
        String dst = ticket.get(1);
        if(!map.containsKey(src)){
            PriorityQueue<String> pq = new  PriorityQueue<String>();
            map.put(src,pq);
        }
        //给队列中放入目的地,同一个起源地可能有多个,但是会自动排序
        map.get(src).add(dst);
    }

    dfs("JFK");
    return res;
    }

    private void dfs(String src){
    // 知道起源地,取出对应的目的地队列
        PriorityQueue<String> pq = map.get(src);
        while(pq!=null&&pq.size()!=0){  //通过while循环,找到最后一个目的地
        dfs(pq.poll());
        }
        res.addFirst(src);
    }
}

51. N 皇后

java版本讲得很好:

class Solution {
     List<List<String>> res = new ArrayList<>(); 
     boolean [][] board;
     HashSet<Integer> col;
     HashSet<Integer> pie,na;
     int n;

    public List<List<String>> solveNQueens(int n) {
        this.n = n;
        this.board = new boolean[n][n];
        this.col = new HashSet<>();
        this.pie = new HashSet<>();
        this.na = new HashSet<>();

        dfs(0);
        return res;
    }

    private void dfs(int i){
        //边界条件 i表示行
        if(i == n){
            generate();
            return; //将结果传入集合中
        }
     // j是列
      for(int j =0;j<n;j++){
          if(col.contains(j)||pie.contains(i+j)||na.contains(i-j)) continue;

          board[i][j] = true;
          col.add(j);
          pie.add(i+j);
          na.add(i-j);

          dfs(i+1);

          board[i][j] = false;
          col.remove(j);
          pie.remove(i+j);
          na.remove(i-j);
      }
    }

    // 对应的board的值转换为结果需要返回的list

    private void generate(){
        ArrayList<String> list = new ArrayList<>();
        for(int i=0;i<n;i++){
            StringBuilder sb = new StringBuilder();
            for(int j =0;j<n;j++){
                if(board[i][j]){
                    sb.append("Q");
                }else{
                    sb.append(".");
                }
            }
             list.add(sb.toString()); // 按照每行添加
        }
       res.add(new ArrayList<>(list));
    }
}

方法二:对其中的col和pie和na都同时表示是否被前面的皇后映射到了,所以就可以用数组表示

class Solution {
     List<List<String>> res = new ArrayList<>(); 
     boolean [][] board;
     boolean [] col,pie,na;
     int n;

    public List<List<String>> solveNQueens(int n) {
        this.n = n;
        this.board = new boolean[n][n];
        this.col =  new boolean[n];
        this.pie = new boolean[n*2];
        this.na =  new boolean[100];

        dfs(0);
        return res;
    }

    private void dfs(int i){
        //边界条件 i表示行
        if(i == n){
            generate();
            return; //将结果传入集合中
        }
     // j是列
      for(int j =0;j<n;j++){
          if(col[j]||pie[i+j]||na[i-j+n] ) continue;

          board[i][j] = true;
          col[j] = true;
          pie[i+j]= true;
          na[i-j+n]= true;

          dfs(i+1);

          board[i][j] = false;
           col[j] = false;
          pie[i+j]= false;
          na[i-j+n]= false;

      }
    }

    // 对应的board的值转换为结果需要返回的list

    private void generate(){
        ArrayList<String> list = new ArrayList<>();
        for(int i=0;i<n;i++){
            StringBuilder sb = new StringBuilder();
            for(int j =0;j<n;j++){
                if(board[i][j]){
                    sb.append("Q");
                }else{
                    sb.append(".");
                }
            }
             list.add(sb.toString()); // 按照每行添加
        }
       res.add(new ArrayList<>(list));
    }
}

这个讲的很暴力
函数1:需要dfs回溯(按照行),函数2:需要检查该点的上面的和左上,右上是否有皇后,函数3:把char数组board变成一个list

class Solution {
     List<List<String>> res = new ArrayList<>(); 
     char [][] board;
     int n;
    
    public List<List<String>> solveNQueens(int n) {
       this.n = n;
       board = new char[n][n];
       for(int i =0;i<n;i++){
           Arrays.fill(board[i],'.');
       }
       dfs(0);
       return res;
    }

    private void dfs(int row){
        //边界条件
        if(row == n){
          generate();
            return; 
        }

        for(int i =0;i<n;i++){  //i表示列
          if(check(row,i)){
             board[row][i] = 'Q';
              dfs(row+1);
               board[row][i] = '.';
          }
        }
    }

    private boolean check(int row,int col){
     // 不用检查(row,col)坐标对应的行,因为回溯就是直接从每行开始
        // 1.检查该列是否有
        for(int i=0;i<row;i++){
          if(board[i][col] == 'Q'){ return false;}
        }
        // 2.检查对角线-2.1左上对角线
        int x = row-1,y=col-1;
        while(x>=0&&y>=0){
            if(board[x][y] == 'Q'){return false;}
            x--;
            y--;
        }
        // 2.2检查右上角对角线
        x = row-1;
        y = col+1;
        while(x>=0&&y<n){
            if(board[x][y] == 'Q'){return false;}
            x--;
            y++;
        }
      return true;
    }
       private void generate(){
        ArrayList<String> list = new ArrayList<>();
        for(int i=0;i<n;i++){
           list.add(String.valueOf(board[i]));
            }
              res.add(list);
        }
      
    
}

数组board变成一个list

// 方法一
 private void generate(){
        ArrayList<String> list = new ArrayList<>();
        for(int i=0;i<n;i++){
           list.add(String.valueOf(board[i]));
            }
              res.add(list);
        }
// 方法二

    private void generate(){
        ArrayList<String> list = new ArrayList<>();
        for(int i=0;i<n;i++){
            StringBuilder sb = new StringBuilder();
            for(int j =0;j<n;j++){
                if(board[i][j]){
                    sb.append("Q");
                }else{
                    sb.append(".");
                }
            }
             list.add(sb.toString()); // 按照每行添加
        }
       res.add(new ArrayList<>(list));
    }

37.数独

1.首先找到’.'的坐标,再依次添加1-9判断是否合法
代码随想录得题解

class Solution {
    char[][] board;
    public void solveSudoku(char[][] b) {
     board = b;
      dfs();
    }

    private boolean dfs(){
       for(int i=0;i<9;i++){
           for(int j =0;j<9;j++){
               if(board[i][j]!='.'){
                   continue;
               }
               for(char k ='1';k<='9';k++){
                   if(check(i,j,k)){
                      board[i][j] = k;
                      if(dfs()){
                          return true;
                      }
                      board[i][j] ='.';
                   }
               }
               return false;
           }
       } 
       return true;
    }

 private boolean check(int row,int col, char k){
        //1.检查(row,col)对应的行是否存在相同值
      for (int i = 0; i < 9; i++){
            if (board[row][i] == k){
                return false;
            }
        }
     //2. 检查对应的列
    for (int j = 0; j < 9; j++){
            if (board[j][col] == k){
                return false;
            }
        }
    //3.检查对应的9宫格
    //获取9宫格左上角的左边
     int x = (row / 3) * 3;
     int y = (col / 3) * 3;
     for (int i =x; i < x + 3; i++){
         for (int j = y; j < y + 3; j++){
             if (board[i][j] == k){
                return false;
            }
       }
   }
        return true;
    }
  
}

总结

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值