leetcode_491_递增子序列_中等难度

老规矩,上题:

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值