day01 计划刷题
电话号码的字母组合
-
题意 : 给定只包含数字的字符串,返回能得到的数字所映射的所有字母的组合
*
-
思路 :
- 对于每一个数字,都有其相对应可映射的字母 , 这种映射关系 我们可以用 哈希表来进行存储。
- 通过 dfs 枚举(组合类dfs)。
递归树图示。
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;
}
}
全排列
- 思路 :排列行枚举
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
- 思路 : 排列型枚举+剪枝(同一层出现重复元素 即分支重复)
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;
}
}
}
}
子集
- 思路 : 指数型枚举. 每个位置 有选 和 不选两种情况
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
- 思路 : 考虑如何剪枝
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;
}
}