/**
* 1. 加入当前数字会产生哪些新序列,只要遍历当前存在的序列并比较最后一个数字和当前数字,如果当前数字更大则加入产生新的序列
* 2. 由 1 产生的新序列加上已经存在的序列以及当前数字作为一个新序列起点的情况作为新的结果
* 3. 利用HashSet对list去重
* 4. 最后过滤掉长度不足 2 的序列得到最终结果
*
* nums = [4, 6, 7, 7]
*
* [4] [4]
* [4,6] [4,6],[4],[6]
* [4,6,7] [4,6,7],[4,7],[6,7],[4,6],[4],[6],[7]
* [4,6,7,7] [4,6,7,7],[6,7,7],[4,7,7],[7,7],[4,6,7],[6,7],[4,7],[7],[4,6,7],[6,7],[4,7],[7],[4,6],[6],[4]
*
*
* result => [4,6,7,7],[6,7,7],[4,7,7],[7,7],[4,6,7],[6,7],[4,7],[4,6]
*/
public List<List<Integer>> findSubsequences(int[] nums) {
Set<List<Integer>> dp = new HashSet<>();
Set<List<Integer>> beforeDp;
for (int i = 0; i < nums.length; i++) {
beforeDp = new HashSet<>(dp);
for (List<Integer> before : beforeDp) {
if(nums[i] >= before.get(before.size()-1)) { //加上新追加的列表
List<Integer> temp = new ArrayList<>(before);
temp.add(nums[i]);
dp.add(temp);
}
dp.add(before); //加上之前的列表
}
dp.add(Arrays.asList(nums[i])); //加上当前元素的
}
return dp.stream().filter(list -> list.size() >= 2).collect(Collectors.toList());
}
/**
* 考虑 nums={1,2,3}
*
* holder 的输出(不考虑剪枝和递增):
* [1]
* [1, 2]
* [1, 2, 3]
* [1, 2, 3, 3]
* [1, 2, 3, 3, 2]
* [1, 2, 3, 3, 2, 3]
* [1, 2, 3, 3, 2, 3, 3]
*
* holder 的输出(考虑剪枝和递增):
* [1]
* [1, 2]
* [1, 2, 3]
* [1, 3]
* [2]
* [2, 3]
* [3]
*
* result的结果
* [[1, 2, 3], [1, 2], [2, 3], [1, 3]]
*/
public List<List<Integer>> findSubsequences(int[] nums) { // 递归回溯(dfs) + 剪枝。只处理递增子序列,限制只取List大小>=2,并利用HashSet对List去重。
List<Integer> holder = new ArrayList<>();
Set<List<Integer>> result = new HashSet<>();
dfs(0, nums, holder, result);
return new ArrayList<>(result);
}
private void dfs(int index, int[] nums, List<Integer> holder, Set<List<Integer>> result) {
if(holder.size() >= 2) {
result.add(new ArrayList<>(holder));
}
for (int k = index; k < nums.length; k++) {
if (holder.isEmpty() || nums[k] >= holder.get(holder.size() - 1)) { // 限制只处理 递增子序列
holder.add(nums[k]);
dfs(k + 1, nums, holder, result);
holder.remove(holder.size() - 1);
}
}
}