Given an integer array, your task is to find all the different possible increasing subsequences of the given array, and the length of an increasing subsequence should be at least 2 .
Example:
Input: [4, 6, 7, 7] Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
Note:
- The length of the given array will not exceed 15.
- The range of integer in the given array is [-100,100].
- The given array may contain duplicates, and two equal integers should also be considered as a special case of increasing sequence.
我的思路是用递归with memory来做,返回 一定以某个索引元素开头 的序列集合。如 [3,3,1,4],先求以 index=0 开头的索引集合,发现3连续出现2次,前缀集合就是 [3] , [3,3],然后递归求出后缀:以 下一个>=1大的数 开头的序列集合,就是 [4] 。将前缀分别加到后缀 [4] 上,得到 [3,4] , [3,3,4] 。在求结果集合时,只要把 以每个索引为开头 的情况都考虑一下,就好了。对了,不要忘记 递增子序列长度要大于等于2,因此还要有过滤操作。
为什么最后要用hashset筛除重复序列呢?会出现重复序列吗?答案是肯定的,看如下例子。
如果input是 [1,5,1,1] 的话,以索引0开头的序列会出现:[1] , [1,1] , [1,1,1] ,而以索引2开头的序列会出现:[1] , [1,1] ,这就出现重复了。
public List<List<Integer>> findSubsequences(int[] nums) {
List<List<Integer>> result=new ArrayList<List<Integer>>();
HashSet<List<Integer>> set=new HashSet<List<Integer>>();
HashMap<Integer, List<List<Integer>>> map=new HashMap<Integer, List<List<Integer>>>();
for(int i=0;i<nums.length;i++){
List<List<Integer>> list=helper(i, nums, map);
for(List<Integer> tmp:list){
if(tmp.size()>=2){
if(!set.contains(tmp)){
result.add(tmp);
set.add(tmp);
}
}
}
}
return result;
}
//返回一定以某个index元素开头的序列集合
public List<List<Integer>> helper(int index,int[] nums,
HashMap<Integer, List<List<Integer>>> map){
if(map.get(index)!=null){
return map.get(index);
}
List<List<Integer>> result=new ArrayList<List<Integer>>();
int nextIndex=index+1;
int count=1;
//得到nums[index]数连续出现个数
while(nextIndex<nums.length&&nums[nextIndex]==nums[index]){
count++;
nextIndex++;
}
for(int nowCount=1;nowCount<=count;nowCount++){
List<Integer> tmp=new ArrayList<Integer>();
for(int j=0;j<nowCount;j++){
tmp.add(nums[index]);
}
result.add(tmp);
}
int prefixSize=result.size();
while(nextIndex<nums.length){
//得到下一个大于等于当前数的index
while(nextIndex<nums.length&&nums[nextIndex]<nums[index]){
nextIndex++;
}
if(nextIndex<nums.length){
List<List<Integer>> nextList=helper(nextIndex, nums, map);
for(int i=0;i<prefixSize;i++){
List<Integer> prefix=result.get(i);
for(List<Integer> postFix:nextList){
List<Integer> tmp=new ArrayList<Integer>(prefix);
tmp.addAll(postFix);
result.add(tmp);
}
}
}
//得到下一个不等于nextIndex的数
int i=nextIndex+1;
while(i<nums.length&&nums[i]==nums[nextIndex]){
i++;
}
nextIndex=i;
}
return result;
}
大神的方法比我快,也比我简洁多了。
使用set是为了避免重复,如 [1,2,3,2]
如果不用set,output将会是 : [[1,2],[1,2,3],[1,2,2],[1,3],[1,2],[2,3],[2,2]]
如果用set,output将会是 : [[1,2],[2,2],[1,3],[2,3],[1,2,3],[1,2,2]]
public class Solution {
public List<List<Integer>> findSubsequences(int[] nums) {
Set<List<Integer>> res= new HashSet<List<Integer>>();
List<Integer> holder = new ArrayList<Integer>();
findSequence(res, holder, 0, nums);
List result = new ArrayList(res);
return result;
}
public void findSequence(Set<List<Integer>> res, List<Integer> holder, int index, int[] nums) {
if (holder.size() >= 2) {
res.add(new ArrayList(holder));
}
for (int i = index; i < nums.length; i++) {
if(holder.size() == 0 || holder.get(holder.size() - 1) <= nums[i]) {
holder.add(nums[i]);
findSequence(res, holder, i + 1, nums);
holder.remove(holder.size() - 1);
}
}
}
}