第 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 题 间隔连续问题的主要内容,如果未能解决你的问题,请参考以下文章
2022-11-18:给定一个数组arr,表示连续n天的股价,数组下标表示第几天 指标X:任意两天的股价之和 - 此两天间隔的天数 比如 第3天,价格是10 第9天,价格是30 那么第3天和第9天的指