1 解题思想
hi,好久不见,最近有点忙,更新的很慢。
这道题是给了一个已经排好序的数组,让你找出所有的子序列,这些子序列要求同样是不下降的(就是i+1的数肯定大于等于i),相同的序列不能重复出现,但是允许某个数重复(所以是不重复)。
我给的是最简单的一个方式,直接回溯,递归去找,使用一个hashset去帮助筛选重复。这里我只加了一个小的优化,就是next,比如3776这样的,当指针在3时,会首先尝试第一个7,然后直接跳过第二个7到6,这样可以节省搜索。
这不是最优解,其实有个解法是:
统计独立出现的所有数和其频率
根据这个数再去生成结果,可以节省很多搜索时间,例如:
337789
Step1:统计 3:2,7:2,8:1,9:1
Step2:递归还原,每一步两个选择(意思是都要尝试),若当前的那个数使用的次数还够,那么-1后重复Step2,若还有下一个数,那么跳过当前数直接到下一个数
每一步Step2的时候,检查下长度,就可以加入到结果中了,而且这个不需要hashSet,不会重复的。
抱歉,我刚写的时候理解的不是很好,所以给的答案不是后面想到那种方式。
微博同名
2 原题
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.
3 AC解
public class Solution {
/**
* 这道题有个很好玩的点:那就是在hashset当中放入数组时,其检查的是这个数组里面的数值是否是一样的,而不是单纯按照对象的地址
* */
public List<List<Integer>> findSubsequences(int[] nums) {
Set<List<Integer>> res= new HashSet<List<Integer>>();
List<Integer> tmp = new ArrayList<Integer>();
int[] next = new int[nums.length];
for(int i=0;i<nums.length;i++){
int my_next = i+1;
while(my_next<nums.length && nums[i]==nums[my_next])
my_next++;
next[i] = my_next;
}
helper(res,tmp,nums,next,0);
return new ArrayList<List<Integer>>(res);
}
/**
* 采用回溯的方式不停地递归,寻找解决方法
* 其实还有更简单的方式,但这里就不多说了
* */
private void helper(Set<List<Integer>> res,List<Integer> tmp,int[] nums,int[] next,int index){
if(tmp.size() > 1){
res.add(new ArrayList<Integer>(tmp));
}
int i=index;
for(;i<nums.length;){
if(tmp.size()==0 || tmp.get(tmp.size() - 1) <= nums[i]){
tmp.add(nums[i]);
helper(res,tmp,nums,next,i+1);
tmp.remove(tmp.size() - 1);
}
//快速跳到下一个上
i = next[i];
}
}
}