Leetcode_659_分隔数组为连续子序列_贪心

12/4

初步思路与标程完全相反,不过是可行的
第一步也是用两个map分别存各个数出现的次数以及以x结尾的子序列数
不同的是,我是让数组数尽量的多
以12345为例
先处理第一个1
将23加入1这个子序列
当子序列长度达到3以后,就不再处理这个子序列,
并让以3结尾的子序列数+1(注意,第二个map的子序列全部都是长度超过3的)
接着处理4,将5加入子序列,此时子序列为45,长度不足3
所以除非有一个以3结尾的长度超过3的子序列,不然返回false
显示是有的(就是123),那么将第二个map里3的值-1,5的值+1
但这么做显然太浪费空间了

标程思路

标程的解析写太好了,直接搬了

初始时,每个数字的剩余次数即为每个数字在数组中出现的次数,因此遍历数组,初始化第一个哈希表。

在初始化第一个哈希表之后,遍历数组,更新两个哈希表。只有当一个数字的剩余次数大于 00 时,才需要考虑这个数字是否属于某个子序列。假设当前元素是 xx,进行如下操作。

首先判断是否存在以 x-1x−1 结尾的子序列,即根据第二个哈希表判断 x-1x−1 作为结尾的子序列的数量是否大于 00,如果大于 00,则将元素 xx 加入该子序列中。由于 xx 被使用了一次,因此需要在第一个哈希表中将 xx 的剩余次数减 11。又由于该子序列的最后一个数字从 x-1x−1 变成了 xx,因此需要在第二个哈希表中将 x-1x−1 作为结尾的子序列的数量减 11,以及将 xx 作为结尾的子序列的数量加 11。

否则,xx 为一个子序列的第一个数,为了得到长度至少为 33 的子序列,x+1x+1 和 x+2x+2 必须在子序列中,因此需要判断在第一个哈希表中 x+1x+1 和 x+2x+2 的剩余次数是否都大于 00。

当 x+1x+1 和 x+2x+2 的剩余次数都大于 00 时,可以新建一个长度为 33 的子序列 [x,x+1,x+2][x,x+1,x+2]。由于这三个数都被使用了一次,因此需要在第一个哈希表中将这三个数的剩余次数分别减 11。又由于该子序列的最后一个数字是 x+2x+2,因此需要在第二个哈希表中将 x+2x+2 作为结尾的子序列的数量加 11。

否则,无法得到长度为 33 的子序列 [x,x+1,x+2][x,x+1,x+2],因此无法完成分割,返回 \text{false}false。

如果整个数组遍历结束时,没有遇到无法完成分割的情况,则可以完成分割,返回 \text{true}true。

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/split-array-into-consecutive-subsequences/solution/fen-ge-shu-zu-wei-lian-xu-zi-xu-lie-by-l-lbs5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    public boolean isPossible(int[] nums) {
        Map<Integer,Integer>cnt = new HashMap<Integer,Integer>();
        Map<Integer,Integer>end = new HashMap<Integer,Integer>();
        for(int i:nums){
            cnt.put(i,cnt.getOrDefault(i,0)+1);
        }
        for(int i:nums){
            int pre=cnt.getOrDefault(i,0);
            while(pre>0){
                pre--;
                int x=end.getOrDefault(i-1,0);
                if(x!=0){
                    end.put(i,end.getOrDefault(i,0)+1);
                    end.put(i-1,x-1);
                    continue;
                }
                x=cnt.getOrDefault(i+1,0);
                int y=cnt.getOrDefault(i+2,0);
                if(x==0||y==0){
                    return false;
                }
                cnt.put(i+1,x-1);
                cnt.put(i+2,y-1);
                end.put(i+2,end.getOrDefault(i+2,0)+1);
            }
            cnt.put(i,0);
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值