分割回文串
用dp提前判断好是否为回文
class Solution {
public List<List<String>> partition(String s) {
int n = s.length();
//转换为字符串数组
char[] cs = s.toCharArray();
// f[i][j] 代表 [i, j] 这一段是否为回文串
boolean[][] f = new boolean[n][n];
//回溯之前dp判断好是否为回文
for (int j = 0; j < n; j++) {
for (int i = j; i >= 0; i--) {
// 当 [i, j] 只有一个字符时,必然是回文串
if (i == j) {
f[i][j] = true;
} else {
// 当 [i, j] 长度为 2 时,满足 cs[i] == cs[j] 即回文串
if (j - i + 1 == 2) {
//相当于 f[i][j] = (cs[i]==cs[j]) 这个为真即为真,反之亦然
f[i][j] = cs[i] == cs[j];
// 当 [i, j] 长度大于 2 时,满足 (cs[i] == cs[j] && f[i + 1][j - 1]) 即回文串
} else {
f[i][j] = cs[i] == cs[j] && f[i + 1][j - 1];
}
}
}
}
List<List<String>> ans = new ArrayList<>();
List<String> cur = new ArrayList<>();
dfs(s, 0, ans, cur, f);
return ans;
}
/**
* s: 要搜索的字符串
* u: 以 s 中的那一位作为回文串分割起点
* ans: 最终结果集
* cur: 当前结果集
* f: 快速判断 [i,j] 是否为回文串
*/
void dfs(String s, int u, List<List<String>> ans, List<String> cur, boolean[][] f) {
int n = s.length();
if (u == n) ans.add(new ArrayList<>(cur));
for (int i = u; i < n; i++) {
if (f[u][i]) {
cur.add(s.substring(u, i + 1));
//substring(0,2)这个只含开头不含结尾,所以要i+1。
dfs(s, i + 1, ans, cur, f);
cur.remove(cur.size() - 1);//移除最后一个元素
}
}
}
}
子集
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
dfs(nums,0);
return res;
}
public void dfs(int[]nums,int begin){
int n= nums.length;
if(begin==n){
res.add(new ArrayList<>(path));
return;
}
path.add(nums[begin]);
dfs(nums,begin+1);
path.remove(path.size()-1);//跳过当前节点,继续搜
dfs(nums,begin+1);
}
}
子集2
这题和上题不同在于需要进行一个去重的操作,这里我们采用两种方式 一种使用set来进行去重,一种使用一个used数组来进行判重
used数组版本:
关于Java代码subsetsWithDupHelper for循环中if判断条件为什么是!used[i - 1]的理解: 表面上,continue条件应该是前一个元素被使用过,这里跟正常逻辑相悖; 仔细想想,如果used[i - 1]被标记为1, 说明该元素刚被使用过且未回溯,那么就算第i个元素和第i-1个元素相等,也可以放心大胆地加到sublist里面,因为加入以后一定比之前元素多一个,不会重复; 相反,如果used[i - 1]被标记为0, 因为现在已经访问到之后的元素了,之前元素一定是被访问过的,那么被标0只有一种可能,就是该元素已经被回溯过了,此时必须跳过当前元素,否则会重复,因为list里面已经有相同的sublist.
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
boolean[] used;
public List<List<Integer>> subsetsWithDup(int[] nums) {
if(nums.length==0){
res.add(path);
return res;
}
Arrays.sort(nums);
used=new boolean[nums.length];
dfs(nums,0);
return res;
}
public void dfs(int[]nums,int begin){
res.add(new ArrayList<>(path));// 收集子集,要放在终止添加的上面,否则会漏掉自己
for(int i=begin;i<nums.length;i++){
if(i>0&&!used[i-1]&&nums[i]==nums[i-1]){
continue;
}
path.add(nums[i]);
used[i]=true;
dfs(nums,i+1);
path.remove(path.size()-1);
used[i]=false;
}
}
}
set版本:
class Solution {
Set<List<Integer>> res = new HashSet<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
dfs(nums,0);
return new ArrayList<>(res);
}
public void dfs(int[]nums,int begin){
if(nums.length==begin){
res.add(new ArrayList<>(path));
return;
}
path.add(nums[begin]);
dfs(nums,begin+1);
path.remove(path.size()-1);
dfs(nums,begin+1);
}
}