老规矩,上题:
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例:
输入: [4, 6, 7, 7]
输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
说明:
给定数组的长度不会超过15。
数组中的整数范围是 [-100,100]。
给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/increasing-subsequences
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
整个题目感觉比较中规中矩,不算难。
总体来说:使用哈希记录一下此次加入答案列表ans的列表p。记录方式为,以p为键,以p的最后一个元素在nums中所在位置(即下标)i为值,形成一个Map,加入到总体的ACMap中全局记录下来。
每次迭代加入一个元素,即p'的长度比p的长度要大1。
使用一格tem队列将一次整体的遍历结果记录下来,以供下次遍历再用。再使用时就先将tem清空。
比如:假设对于nums = [4, 6, 7, 7]。
①初始时加入ans中两个元素组成的递增序列,即ans = [[4,6], [4,7], [6,7], [7,7]]。
同时,使用ACMap记录下键值对,如记录[4,6]时,则为{[4,6]:1},因为‘6’在nums中的下标为'1'。
其他同理。
②遍历ans:
while(!ans.isEmpty()){
LinkedList<Integer> l = new LinkedList<>(ans.remove(0));
int s = ac.get(l) + 1; //取出最后一个元素在nums中对应的下标的后一个位置
int n1 = l.get(l.size()-1); //的值
while(s < len){ //从nums[s->len)这一段中,每次加入一个元素,枚举
LinkedList<Integer> p = new LinkedList<>(l);
int n2 = nums[s++];
p.addLast(n2);
//如果此时ans[0]中最后一个元素,以及其在nums中对应位置处的后一个元素满足递增,同时ACMap中还未记录该list,则加入新的ans中,同时在ACMap中记录下来
if(n1<=n2 && !ac.containsKey(p)){
System.out.println("add "+p);
ac.put(p, s-1); //注意这里是(s-1)!!!因为前面已经让s自加了
tem.add(p);
}
}
}
③最后再更新ans:
if(tem.isEmpty()) break; //如果为空则说明在第②步中没有一个的元素装填形成新的list,很明显,此后再也没有满足条件的元素,直接break即可
// ans.addAll(tem);
ans.addAll(tem); //使用新的加入新元素的列表来重新装填ans(因为在遍历枚举的时候ans清空了)
tem.clear(); //将tem清空以便下一次遍历使用
④重复②③即可,直至内部break。
实现:java版
package leetcode;
import java.util.*;
/*
USER:LQY
DATE:2020/8/25
TIME:8:50
*/
public class leetcode_491_递增子序列 {
public static void main(String []args){
int []nums = {4, 6, 7, 7};
new leetcode_491_递增子序列().findSubsequences(nums);
}
public List<List<Integer>> findSubsequences(int[] nums) {
List<List<Integer>> ans = new LinkedList<>();
Map<List<Integer>, Integer> ac = new HashMap<>();
int len = nums.length;
if(len == 1) return ans;
for(int i = 0;i < len;i++){
int n1 = nums[i];
for(int j = i+1;j < len;j++){
int n2 = nums[j];
if(n1<=n2 && !ac.containsKey(Arrays.asList(n1,n2))){
// if(ac.containsKey(Arrays.asList(n1,n2))) continue;
ans.add(Arrays.asList(n1,n2));
ac.put(Arrays.asList(n1,n2), j);
}
}
}
if(ans.isEmpty()) return ans;
LinkedList<List<Integer>>tem = new LinkedList<>();
while(true){
System.out.print("this time :");
for(List i: ans){
for(Object j: i){
System.out.print(j+" ");
}
System.out.println();
}
System.out.println();
while(!ans.isEmpty()){
LinkedList<Integer> l = new LinkedList<>(ans.remove(0));
int s = ac.get(l) + 1; //取出最后一个元素在nums中对应的下标的后一个位置
int n1 = l.get(l.size()-1); //的值
while(s < len){ //从nums[s->len)这一段中,每次加入一个元素,枚举
LinkedList<Integer> p = new LinkedList<>(l);
int n2 = nums[s++];
p.addLast(n2);
//如果此时ans[0]中最后一个元素,以及其在nums中对应位置处的后一个元素满足递增,同时ACMap中还未记录该list,则加入新的ans中,同时在ACMap中记录下来
if(n1<=n2 && !ac.containsKey(p)){
System.out.println("add "+p);
ac.put(p, s-1); //注意这里是(s-1)!!!因为前面已经让s自加了
tem.add(p);
}
}
}
if(tem.isEmpty()) break;
System.out.println("next time :");
for(List i: tem){
for(Object j: i){
System.out.print(j+" ");
}
System.out.println();
}
System.out.println();
// ans.addAll(tem);
ans.addAll(tem);
tem.clear();
}
System.out.println("the answer:");
ans.clear();
ans.addAll(ac.keySet());
for(List l: ac.keySet()){
for(Object i: l){
System.out.print(i+" ");
}
System.out.println();
}
//
for(Map.Entry k: ac.entrySet()){
System.out.println(k.getKey()+":"+k.getValue());
}
return ans;
}
}