算法刷题 DFS+回溯专题 day01

93 阅读1分钟

day01 计划刷题

电话号码的字母组合

全排列

全排列 II

子集

子集 II

电话号码的字母组合

  • 题意 : 给定只包含数字的字符串,返回能得到的数字所映射的所有字母的组合 image.png*

  • 思路 :

    • 对于每一个数字,都有其相对应可映射的字母 , 这种映射关系 我们可以用 哈希表来进行存储。
    • 通过 dfs 枚举(组合类dfs)。

递归树图示。

4c0b45d06eff63b3f1443d4db3ee444.png

code
class Solution {
       static  HashMap<String,String> map = new HashMap<>() {
            {
                put("2","abc");
                put("3","def");
                put("4","ghi");
                put("5","jkl");
                put("6","mno");
                put("7","pqrs");
                put("8","tuv");
                put("9","wxyz");
            }
        };
    public List<String> letterCombinations(String digits) {
    if (digits.length() == 0 || null == digits ) return new ArrayList<>();
   

        return  dfs(digits,"",new ArrayList<>(),0);
    }

    private List<String> dfs(String digits,String path,List<String> ans , int i) {
        if (i == digits.length()) {
            ans.add(path);
            return ans;
        }
        // substring [)
        String t = map.get(digits.substring(i,i+1));
        for (int j = 0 ; j < t.length();j ++) {
            dfs(digits,path + t.charAt(j),ans,i + 1);
        }
        return ans;
    }

}

全排列

  • 思路 :排列行枚举

15ae3ea7ad21a7a32ad3a3fc0684490.png

code
class Solution {
    List<List<Integer>> ans ;
    List<Integer> s ;
    boolean[] isUse ;
    public List<List<Integer>> permute(int[] nums) {
        ans = new ArrayList<>();
        s = new ArrayList<>();
        isUse = new boolean[nums.length];
        dfs (0 , nums);
        return ans;
    }
    
    private void dfs(int level , int[] nums) {
        if (level == nums.length ) {
            ans.add(new ArrayList<>(s));
                return;
        }
        
        for (int i = 0 ; i < nums.length ; i ++){
            if (!isUse[i]) {
                    s.add(nums[i]);
                    isUse[i] = true; 
                    System.out.println(s);
                    dfs(level + 1 , nums);
                    s.remove(s.size() - 1);
                    isUse[i] = false;
            }
        }
    }
}

全排列 II

  • 思路 : 排列型枚举+剪枝(同一层出现重复元素 即分支重复)

fdd6569defc36a25cf7137ce7964df6.jpg

class Solution {
    List<List<Integer>> ans ;
    List<Integer> s ;
    boolean[] isUse ;
    public List<List<Integer>> permuteUnique(int[] nums) {
        ans = new ArrayList<>();
        s = new ArrayList<>();
        isUse = new boolean[nums.length];
        Arrays.sort(nums);
        dfs (0 , nums);
        return ans;
    }
    
    private void dfs(int level , int[] nums) {
        if (level == nums.length ) {
            ans.add(new ArrayList<>(s));
            return;
        }
        
        for (int i = 0 ; i < nums.length ; i ++){
            if (i > 0 && nums[i - 1] == nums[i] && !isUse[i - 1]) continue;
            if (!isUse[i] ) {
                    s.add(nums[i]);
                    isUse[i] = true; 
                    dfs(level + 1 , nums);
                    s.remove(s.size() - 1);
                    isUse[i] = false;
            }
        }
    }
}

子集

  • 思路 : 指数型枚举. 每个位置 有选 和 不选两种情况

c6126f84a2e432344b3a8e8c05d39af.jpg

class Solution {
    private List<List<Integer>> ans;
    private List<Integer> s;
    public List<List<Integer>> subsets(int[] nums) {
            ans = new ArrayList<List<Integer>>();
            s = new ArrayList<>();
            dfs(nums,0);
            return ans;
    }

    private void dfs(int[] nums , int idx) {
        if (idx == nums.length){
            ans.add(new ArrayList<Integer>(s));
             return;
        }
        // no
        dfs(nums,idx + 1);

        //yes
        s.add(nums[idx]);
        dfs(nums,idx + 1);
        s.remove(s.size() - 1);

    }

}

子集 II

  • 思路 : 考虑如何剪枝

40bb861348e422d6784c65118835129.jpg

class Solution {
     private List<List<Integer>> ans;
    private List<Integer> s;
    private boolean isUse[];
    public List<List<Integer>> subsetsWithDup(int[] nums) {
            ans = new ArrayList<List<Integer>>();
            s = new ArrayList<>();
            isUse = new boolean[nums.length];
            Arrays.sort(nums);
            dfs(nums,0);
            return ans;
    }
    private void dfs(int[] nums , int idx) {
        if (idx == nums.length ){
            ans.add(new ArrayList<Integer>(s));
             return;
        }
        // no
        dfs(nums,idx + 1);

        // 放数字的时候 若前面的数字没有被使用则不能放置
        if(idx > 0 && nums[idx] == nums[idx - 1] && !isUse[idx - 1]) return ;
        //yes
        s.add(nums[idx]);
        isUse[idx] = true;
        dfs(nums,idx + 1);
        s.remove(s.size() - 1);
        isUse[idx] = false;

    }

}