第 3 题 间隔连续问题

Posted NC_NE

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第 3 题 间隔连续问题相关的知识,希望对你有一定的参考价值。

1、题目要求

        某游戏公司记录的用户每日登录数据,计算每个用户最大的连续登录天数,可以间隔一天。解释:如果一个用户在 1,3,5,6 登录游戏,则视为连续 6 天登录。

1002;2021-12-12
1001;2021-12-13
1001;2021-12-14
1001;2021-12-16
1002;2021-12-16
1001;2021-12-19
1002;2021-12-17
1001;2021-12-20

2、建表和加载数据

create table if not exists test3(
id int,
dt string
)row format delimited fields terminated by ";";


load data local inpath '/opt/test/t3.txt' overwrite into table test3;

3、分析

第1题我们做过连续问题,我们使用的等差数列的概念,即如果连续他们的间隔是相等的,但是本题是间隔连续,它不是完全连续,它允许间隔不一样,即在我设置的值内就算连续,比如

设置间隔小于三
10 11 13 15 16  前后两个数的间隔小于三,所以这五个数字连续
21 25 29 前后间隔25和21不小于三,25和29也不小于三,所以这三个数字不连续

方法一:等差法

        1、先分组排序

1001 2021-12-13 1
1001 2021-12-14 2
1001 2021-12-16 3
1001 2021-12-19 4
1001 2021-12-20 5
1002 2021-12-12 1
1002 2021-12-16 2
1002 2021-12-17 3

        2、在相减

1001 2021-12-13 1 2021-12-12
1001 2021-12-14 2 2021-12-12
1001 2021-12-16 3 2021-12-13
1001 2021-12-19 4 2021-12-15
1001 2021-12-20 5 2021-12-15
1002 2021-12-12 1 2021-12-11
1002 2021-12-16 2 2021-12-14
1002 2021-12-17 3 2021-12-14

        3、在对相减后的数据重新再来一遍分组排序,相减

1001 2021-12-13 1 2021-12-12 1 2021-12-11
1001 2021-12-14 2 2021-12-12 1 2021-12-11
1001 2021-12-16 3 2021-12-13 2 2021-12-11
1001 2021-12-19 4 2021-12-15 3 2021-12-12
1001 2021-12-20 5 2021-12-15 3 2021-12-12
1002 2021-12-12 1 2021-12-11 1 2021-12-10
1002 2021-12-16 2 2021-12-14 2 2021-12-12
1002 2021-12-17 3 2021-12-14 2 2021-12-12

        到这就可以计算出间隔一天的连续时间了,这样做太繁琐了,如果间隔三天,四天,那太麻烦,而却sql扩展太差。

方法二:分组法

        思考:如果我能够将间隔一天和间隔两天的数据分到同一个组里面,那就可以知道最大连续天数,结合第2题 分组问题,我们是不是可以有点想法,

        1、我们使用lag函数开窗将当前行的上一行数据下移

select 
id,dt,
lag(dt,1,'1970-01-01') over(partition by id order by dt) lagdt
from test3;

        结果:

id	         dt	        lagdt
1001	2021-12-13	1970-01-01
1001	2021-12-14	2021-12-13
1001	2021-12-16	2021-12-14
1001	2021-12-19	2021-12-16
1001	2021-12-20	2021-12-19
1002	2021-12-12	1970-01-01
1002	2021-12-16	2021-12-12
1002	2021-12-17	2021-12-16

        2、用当前行减上一行 datediff(dt - lagdt)

select 
id,dt,
datediff(dt,lagdt) dtdiff
from (
select 
id,dt,
lag(dt,1,'1970-01-01') over(partition by id order by dt) lagdt
from test3
)t1;

        结果:

id	        dt	    dtdiff
1001	2021-12-13	18974
1001	2021-12-14	1
1001	2021-12-16	2
1001	2021-12-19	3
1001	2021-12-20	1
1002	2021-12-12	18973
1002	2021-12-16	4
1002	2021-12-17	1

        3、分组,因为是间隔一天也算连续,所以,相减后小于等于2的都是连续(后续如果间隔两天也算,就小于等于3都是连续)

sum(if(dtdiff>2,1,0)) over(partition by id order by dt) groupid

select
    id,dt,
    sum(if(dtdiff>2,1,0)) over(partition by id order by dt) groupid
from (
    select 
        id,dt,
        datediff(dt,lagdt) dtdiff
    from (
        select 
            id,dt,
            lag(dt,1,'1970-01-01') over(partition by id order by dt) lagdt
        from test3
    )t1
)t2;

        结果:

id	        dt     groupid
1001	2021-12-13	1
1001	2021-12-14	1
1001	2021-12-16	1
1001	2021-12-19	2
1001	2021-12-20	2
1002	2021-12-12	1
1002	2021-12-16	2
1002	2021-12-17	2

        4、按照用户和groupid分组,求最大时间减去最小时间

select 
    id,groupid,
    datediff(max(dt),min(dt)) days
from (
    select
        id,dt,
        sum(if(dtdiff>2,1,0)) over(partition by id order by dt) groupid
    from (
        select 
            id,dt,
            datediff(dt,lagdt) dtdiff
        from (
            select 
                id,dt,
                lag(dt,1,'1970-01-01') over(partition by id order by dt) lagdt
            from test3
        )t1
    )t2
)t3
group by id,groupid;

        结果:

id    groupid   days
1001	1	     3
1001	2	     1
1002	1	     0
1002	2	     1

        5、分组取最大登陆天数并加上1,加1的原因也很简单(就比如2021-12-13到2021-12-16,你单纯数字相减那就是3,但实际是4天)

select 
id,
max(days)+1 as days
from (
    select 
        id,groupid,
        datediff(max(dt),min(dt)) days
    from (
        select
            id,dt,
            sum(if(dtdiff>2,1,0)) over(partition by id order by dt) groupid
        from (
            select 
                id,dt,
                datediff(dt,lagdt) dtdiff
            from (
                select 
                    id,dt,
                    lag(dt,1,'1970-01-01') over(partition by id order by dt) lagdt
                from test3
            )t1
        )t2
    )t3
    group by id,groupid
)t4
group by id;

        结果:

id      days
1001     4
1002     2

以上是关于第 3 题 间隔连续问题的主要内容,如果未能解决你的问题,请参考以下文章

第 2 题 分组问题

移动序列

2022-11-18:给定一个数组arr,表示连续n天的股价,数组下标表示第几天 指标X:任意两天的股价之和 - 此两天间隔的天数 比如 第3天,价格是10 第9天,价格是30 那么第3天和第9天的指

第 1 题 连续问题

SQL GROUP BY:连续的间隔?

JavaScript笔试题(js高级代码片段)