思考过程:
输入的数组长度为n,那么子序列的长度范围是[2,n],而且长度为3的子序列,一定是在长度2的基础上,再往右找,依次,所以应该先找所有长度2的子序列,在此基础上找到3,一直到n
要找到长度为2的子序列,遍历两遍即可,记录下每一种满足情况的数组和最右边的位置,考虑到会有重复的,用set存两个值拼接的字符去重。
得到所有长度为2的子序列后,从3-n遍历,再遍历每一种满足情况的数组,从最右的位置依次移动到len,判断是否满足。
代码实现:
public List<List<Integer>> findSubsequences(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
//找到所有长度为2的子序列
Set<String> set = new HashSet<>();
List<String> leftRight = new ArrayList<>();
Map<String, List<Integer>> map = new HashMap<>();
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] >= nums[i] && !set.contains(nums[i] + "-" + nums[j])) {
List<Integer> tem = new ArrayList<>();
tem.add(nums[i]);
tem.add(nums[j]);
ans.add(new ArrayList<>(tem));
map.put(i + "-" + j, new ArrayList<>(tem));
set.add(nums[i] + "-" + nums[j]);
leftRight.add(i + "-" + j);
}
}
}
Map<String, List<Integer>> temMap = new HashMap<>();
List<String> temLeftRight = new ArrayList<>();
//在长度为2的子序列的基础上,找到长度3-n的子序列
for (int len = 3; len <= nums.length; len++) {
temMap.clear();
temLeftRight.clear();
for (String s : leftRight) {
String[] ss = s.split("-");
int right = Integer.parseInt(ss[ss.length - 1]);
List<Integer> lastJ = new ArrayList<>();
for (int j = right + 1; j < nums.length; j++) {
if (nums[j] >= nums[right]) {
boolean add = true;
for (int lj : lastJ) {
if (nums[j] == nums[lj]) {
add = false;
}
}
if (add) {
lastJ.add(j);
List<Integer> tem = new ArrayList<>(map.get(s));
tem.add(nums[j]);
ans.add(tem);
temMap.put(s + "-" + j, tem);
temLeftRight.add(s + "-" + j);
}
}
}
}
map.clear();
map.putAll(temMap);
leftRight.clear();
leftRight.addAll(temLeftRight);
}
return ans;
}
执行结果:
总结:
虽然代码执行通过,但是效率极差,而且在实现代码的过程中,并没有一开始就考虑清楚所有的情况,导致是一边测试一边修改代码,发现有问题,再去看代码哪里不对。
解法一是二进制枚举+哈希,思路就是枚举出所有子序列,然后判断是否满足,用hash去重。枚举时用到了一种很巧妙的方法,,用1代表选中,0代表未选中。后面hash去重没有看懂。
官方代码:
//官方代码
List<Integer> temp = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();
Set<Integer> set = new HashSet<Integer>();
int n;
public List<List<Integer>> findSubsequences(int[] nums) {
n = nums.length;
for (int i = 0; i < (1 << n); ++i) {
findSubsequences(i, nums);
int hashValue = getHash(263, (int) 1E9 + 7);
if (check() && !set.contains(hashValue)) {
ans.add(new ArrayList<Integer>(temp));
set.add(hashValue);
}
}
return ans;
}
public void findSubsequences(int mask, int[] nums) {
temp.clear();
for (int i = 0; i < n; ++i) {
if ((mask & 1) != 0) {
temp.add(nums[i]);
}
mask >>= 1;
}
}
public int getHash(int base, int mod) {
int hashValue = 0;
for (int x : temp) {
hashValue = hashValue * base % mod + (x + 101);
hashValue %= mod;
}
return hashValue;
}
public boolean check() {
for (int i = 1; i < temp.size(); ++i) {
if (temp.get(i) < temp.get(i - 1)) {
return false;
}
}
return temp.size() >= 2;
}
执行结果:
效率也不太高。