LeetCode (dfs)

第一题

在这里插入图片描述
在这里插入图片描述

class Solution {

    String[] mapping = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};

    public List<String> letterCombinations(String digits) {
        List<String> state = new ArrayList<>();
        //对空字符串进行特判
        if(digits.length() == 0) return state;

        //先给state加入一个空串
        state.add("");
        char[] chars = digits.toCharArray();
        for(char ch : chars)
        {
            //遍历输入的数字
            char[] temp = mapping[ch - '2'].toCharArray();
            List<String> now = new ArrayList<>();
            //再遍历每个数字对应的字母
            for(char tch : temp)
            {
                //再遍历state集合,把数字对应的字母加入到state集合中的后边
                for(String str : state)
                {
                    now.add(str + tch);
                }
            }
            state = now;
        }
        return state;
    }
}

第二题

在这里插入图片描述
在这里插入图片描述

class Solution {
    int m, n;
    // 定义四个dfs搜索的四个方向
    int[] dx = {1 , 0 , -1 , 0};
    int[] dy = {0 , 1 , 0 , -1};
    public boolean exist(char[][] board, String word) {
        // 判空
        if(board.length == 0 || board[0].length == 0) return false;
        m = board.length;
        n = board[0].length;
        /*
            m: 行数(横坐标)
            n: 列数(纵坐标)
        */
        for(int i = 0 ; i < m ; i++)
        {
            for(int j = 0 ; j < n ; j++)
            {
                //dfs入口
                if(dfs(board, i, j, word, 0))
                {
                    return true;
                }
            }
        }
        return false;
    }
    
    public boolean dfs(char[][] board, int x, int y, String word, int start) {
        // 如果搜索到的字符和表格中的字符不相等,返回false
        if(board[x][y] != word.charAt(start) ) return false;
        // 到这里的话,也就意味着相等,start==word.length() -1 也就是搜索到了word的最后一个字符
        // 说明全部正确,返回true
        if(start == word.length() - 1) return true;
        
        // dfs 不可以重复走,在这里进行标记
        board[x][y] = '.';
        for(int i = 0 ; i < 4 ; i++)
        {
            int mx = x + dx[i];
            int ny = y + dy[i];
            // 判断横纵坐标不可以超过边界
            if(mx >= 0 && mx < m && ny >= 0 && ny < n)
            {
                // start+1,也就是走下一步
                if(dfs(board, mx, ny, word, start + 1)) 
                {
                    return true;
                }
            }
        }
        // 如果走不了的话,在这里回溯 (恢复现场)
        board[x][y] = word.charAt(start);
        return false;
    }
}

第三题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

class Solution {
    
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    int n;
    boolean[] st;
    
    public List<List<Integer>> permute(int[] nums) {
        n = nums.length;
        st = new boolean[n];
        dfs(nums, path, 0);
        return ans;
    }

    public void dfs(int[] nums, List<Integer> path, int index) {
        if(index == nums.length) 
        {
            //注意!这里不能直接将path添加进去,需要new出一个list集合,将path值赋给它
            //然后再添加到ans中
            ans.add(new ArrayList<>(path));
            return ;
        }

        for(int i = 0 ; i < nums.length ; i++)
        {
            //判断数组中第i个数是否使用过
            if(!st[i])
            {
                //标记为已使用 
                st[i] = true;
                path.add(nums[i]);
                dfs(nums, path, index + 1);
                //回溯
                path.remove(path.size() - 1);
                st[i] = false;
            }
        }

    }
}

第四题

在这里插入图片描述

在这里插入图片描述

class Solution {

    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    boolean[] st ;
    int n ;

    public List<List<Integer>> permuteUnique(int[] nums) {
        n = nums.length;
        st = new boolean[n];
        Arrays.sort(nums);
        dfs(nums , 0);
        return ans;
    }

    public void dfs(int[] nums , int start) {
        if(start == n)
        {
            ans.add(new ArrayList<>(path));
            return ;
        }

        for(int i = 0 ; i < n ; i++)
        {
            if(!st[i])
            {
                //在这里去重即可
                //如果第i个数和第i-1个数相同,同时第i-1个数也可以放入集合,所以就不能放第i个数,否则回重复
                if(i > 0 && nums[i] == nums[i-1] && !st[i-1]) continue;
                st[i] = true;
                path.add(nums[i]);
                dfs(nums , start + 1);
                path.remove(path.size() - 1);
                st[i] = false;
            }
        }
    }
}

第五题

在这里插入图片描述

这道题目需要我们去遍历集合
遍历集合最好的方式也就是利用二进制

在这里插入图片描述

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        int n = nums.length;
        // n个元素的话,就从 0枚举到 2^n
        for(int i = 0 ; i < 1<<n ; i++)
        {
            List<Integer> path = new ArrayList<>();
            for(int j = 0 ; j < n ; j++)
            {
                // 判断i的第j为是否是1
                // i >> j & 1 将i右移j位与上1
                if((i >> j & 1) == 1)
                {
                    // i的第j位是1的话,就把数组中的第j个元素添加到集合中
                    path.add(nums[j]);
                }
            }
            ans.add(new ArrayList<>(path));
        }
        return ans;
    }
}

第六题

在这里插入图片描述
在这里插入图片描述

class Solution {

    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    int n;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        n = nums.length;
        //先排序,将相同的数字放在一起
        Arrays.sort(nums);
        dfs(nums, 0);
        return ans;
    }
    public void dfs(int[] nums , int u) {
        //递归终止条件,当所有数都被添加过后,将所得集合添加入ans
        if(u == n)
        {
            ans.add(new ArrayList<>(path));
            return;
        }

        int k = 0;
        // 统计与当前数相同的数的个数
        while(u+k < n && nums[u] == nums[u+k]) k++;

        // 将第u个数,向集合里放 0次、1次 ... k次,直接dfs下个不相同的数,这样就不会重复
        /*
            加入有三个2 : 2 2 2
            将2加入集合1次 {2}: 2次:{2,2} 3次:{2,2,2} 这样不会重复
            如果将第一个2添加一次 {2} 
            将第二个2添加一次 {2}  那么就会造成重复
        */
        for(int i = 0 ; i <= k ; i++)
        {
            dfs(nums , u+k);
            path.add(nums[u]);
        }
        for(int i = 0 ; i <= k ; i++)
        {
            path.remove(path.size() - 1);
        }
    }
}

第七题

在这里插入图片描述

解题思路:

从1开始搜索,递归记录三个参数,(1)搜索到了数字几(2)目前为止搜索到的数字和(3)达成目标和的数的个数

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        //第三个参数存储从哪里开始
        dfs(k , n , 1);
        return ans;
    }
    public void dfs(int k , int n , int start ) {
        if(k == 0)
        {
            if(n == 0)
            {
                //如果k个数组成了n,就添加到结果中
                ans.add(new ArrayList<>(path));
            }
            return ;
        }
        /*
            还可以进一步进行优化:
            从 i~9 最起码需要有k个数: 9-i+1 >= k  ---> i <= 10-k 
            所以下列for循环可以优化为
            for(int i = start ; i <= 10-k ; i++)
        */
        for(int i = start ; i <= 9 ; i++)
        {
            //先把i试着加进去
            path.add(i);
            //下个数要从 i+1开始,而不是start+1
            dfs(k-1, n-i , i+1);
            //回溯
            path.remove(path.size() - 1);
        }
    }
}

第八题

在这里插入图片描述
经典问题 :八皇后
在dfs中,参数传入行数,在每一行中,遍历每一列 即可。
在这里插入图片描述

class Solution {

    // col表示列,d表示正对角线,ud表示反对角线 是否可以放皇后
    boolean[] col , d , ud ;  
    int ans = 0;
    int n;
    public int totalNQueens(int _n) {
        n = _n;
        col = new boolean[n];
        d  = new boolean[2 * n];
        ud = new boolean[2 * n];
        dfs(0);
        return ans;
    }

    public void dfs(int u) {
        // 如果n行都放了皇后的话,说明找到了一个题解,ans+1
        if(u == n)
        {
            ans++;
            return;
        }
        
        // u代表行  i代表列
        for(int i = 0 ; i < n ; i++) 
        {
            // 如果列,对角线都没有皇后
            if(!col[i] && !d[u+i] && !ud[u-i+n])
            {
                // 放一个皇后
                col[i] = d[u+i] = ud[u-i+n] = true;
                dfs(u + 1);
                // 回溯
                col[i] = d[u+i] = ud[u-i+n] = false;
            }
        }
    }
}

第九题

在这里插入图片描述在这里插入图片描述

解题思路:
顺序: 横着走,也就是x ,y++这样走,走到每一行的末尾,x+=1,y=0进行换行,当x=9也就是走完最后一行的时候,走完了九宫格,返回true即可。
认真理清楚逻辑之后,代码还是很好理解的。

class Solution {

    boolean[][] col = new boolean[9][9]; //col[i][j] 表示第i行是否存在数字j
    boolean[][] row = new boolean[9][9]; //row[i][j] 表示第i列是否存在数字j
    boolean[][][] grid = new boolean[3][3][9]; //grid[i][j][k] 表示第i行第j列个九宫格是否存在数字k
    public void solveSudoku(char[][] board) {
        
        for(int i = 0 ; i < 9 ; i++)
        {
            for(int j = 0 ; j < 9 ; j++)
            {
                if(board[i][j] != '.')
                {
                    int temp = board[i][j] - '1';
                    // 初始化三个数组
                    row[i][temp] = col[j][temp] = grid[i/3][j/3][temp] = true;
                }
            }
        }
        dfs(board , 0 , 0);
    }

    public boolean dfs(char[][] board , int x , int y) {
        // 如果走到这一行的尽头,就向下一行走
        if(y == 9)
        {
            x++;
            y = 0;
        }
        // 如果走到最后一行,就说明走完了九宫格,返回true。
        if(x == 9) return true;

        // 如果已经有数,就向下一个位置走
        if(board[x][y] != '.') return dfs(board , x , y+1);

        for(int i = 0 ; i < 9 ; i++)
        {
            // 条件判断
            if(!row[x][i] && !col[y][i] && !grid[x/3][y/3][i])
            {
                // 记得设置代表已经有这个数
                row[x][i] = col[y][i] = grid[x/3][y/3][i] = true;
                // 将数填入表格
                board[x][y] = (char)(i + '1');
                if(dfs(board , x , y+1)) return true;
                // 回溯
                board[x][y] = '.';
                row[x][i] = col[y][i] = grid[x/3][y/3][i] = false;
            }
        }
        return false;
    }
}

122分钟

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页