题解 | #牛客每个人最近的登录日期(五)#

牛客每个人最近的登录日期(五)

http://www.nowcoder.com/practice/ea0c56cd700344b590182aad03cc61b8

我写的长垃圾代码:

select l1.date, 
case when round(l4.cnt_user /  count(l2.user_id),3) then round(l4.cnt_user /  count(l2.user_id),3)
    else round(0.000, 3) end
from login l1
left join(  
    -- 获取到每个用户的首次访问日期  
    select l2.user_id, min(l2.date) as first_date
    from login l2
    group by l2.user_id
)l2 on l1.user_id=l2.user_id  and l1.date=l2.first_date  -- 这个条件设置设置了把不是首次访问的时间置空
left join (
    -- 获取到第一天访问日期后,第二天还访问的人数
    select l3.date, count(t.user_id) as cnt_user, DATE_ADD(l3.date, INTERVAL -1 DAY) as next_day
    from login l3
    inner join (
        -- 获取到每个用户的首次访问日期  
        select user_id, min(date) as first_date
        from login 
        group by user_id
    ) as t on l3.user_id=t.user_id and l3.date=DATE_ADD(t.first_date, INTERVAL 1 DAY)
    group by l3.date
)as l4 on l1.date=l4.next_day
group by l1.date

暂存临时表优化一下:

with user_mindate as(
     -- 获取到每个用户的首次访问日期  
    select user_id, min(date) as first_date
    from login
    group by user_id
)
--  我:费劲千辛万苦的长代码…
select l1.date, 
case when round(l4.cnt_user /  count(l2.user_id),3) then round(l4.cnt_user /  count(l2.user_id),3)
    else round(0.000, 3) end
from login l1
left join user_mindate as l2 on l1.user_id=l2.user_id  
    and l1.date=l2.first_date  -- 这个条件设置设置了把不是首次访问的时间置空
left join (
    -- 获取到第一天访问日期后,第二天还访问的人数
    select l3.date, count(t.user_id) as cnt_user, DATE_ADD(l3.date, INTERVAL -1 DAY) as next_day
    from login l3
    inner join user_mindate as t on l3.user_id=t.user_id and l3.date=DATE_ADD(t.first_date, INTERVAL 1 DAY)
    group by l3.date
)as l4 on l1.date=l4.next_day
group by l1.date

猴哥的思路(牛逼)

SELECT
    a.date,
    ROUND( COUNT( b.user_id ) * 1.0 / COUNT( a.user_id ), 3 ) AS p
FROM
    ( SELECT user_id, MIN( date ) AS date FROM login GROUP BY user_id ) a
    LEFT JOIN login b ON a.user_id = b.user_id
    AND b.date = DATE_ADD(a.date,INTERVAL 1 DAY)
GROUP BY
    a.date UNION
SELECT
    date,
    0.000 AS p
FROM
    login
WHERE
    date NOT IN ( SELECT MIN( date ) FROM login GROUP BY user_id )
ORDER BY
    date;

网上其他人+猴哥,最好的方法!:

--  其他人+猴哥第二个版本,好!
SELECT  d.date, 
round (IFNULL( count(l2.user_id) / count(l1.user_id), 0), 3)
FROM (SELECT date FROM login  group by date ) AS d 
LEFT JOIN (
    SELECT user_id, min(date) as first_day  -- 找出最小日期
    FROM login
    GROUP BY user_id 
) AS l1 ON l1.first_day=d.date 
LEFT JOIN(
    SELECT user_id, date
    FROM login
) as l2 ON l1.user_id=l2.user_id and l2.date=DATE_ADD(l1.first_day, INTERVAL 1 DAY)
GROUP BY d.date
全部评论

相关推荐

自从我室友在计算机导论课上听说了“刷 LeetCode 是进入大厂的敲门砖”,整个人就跟走火入魔了一样。他在宿舍门口贴了一张A4纸,上面写着:“正在 DP,请勿打扰,否则 Time Limit Exceeded。”日记本的扉页被他用黑色水笔加粗描了三遍:“Talk is cheap. Show me the code。”连宿舍聚餐,他都要给我们讲解:“今天的座位安排可以用回溯算法解决,但为了避免栈溢出,我建议用动态规划。来,这是状态转移方程:dp[i][j] 代表第 i 个人坐在第 j 个位置的最优解。”我让他去楼下取个快递,他不直接去,非要在门口踱步,嘴里念念有词:“这是一个图的遍历问题。从宿舍楼(root)到驿站(target node),我应该用 BFS 还是 DFS?嗯,求最短路径,还是广度优先好。”和同学约好出去开黑,他会提前发消息:“集合点 (x, y),我们俩的路径有 k 个交点,为了最小化时间复杂度,应该在 (x/2, y/2) 处汇合。”有一次另一个室友低血糖犯了,让他帮忙找颗糖,他居然冷静地分析道:“别急,这是一个查找问题。零食箱是无序数组,暴力查找是 O(n)。如果按甜度排序,我就可以用二分查找,时间复杂度降到 O(log n)。”他做卫生也要讲究算法效率:“拖地是典型的岛屿问题,要先把连通的污渍区块都清理掉。倒垃圾可以用双指针法,一个指针从左往右,一个从右往左,能最快匹配垃圾分类。”现在我们宿舍的画风已经完全变了,大家不聊游戏和妹子,对话都是这样的:“你 Two Sum 刷了几遍了?”“别提了,昨天遇到一道 Hard 题,我连暴力解都想不出来,最后只能看题解。你呢?”“我动态规划还不行,总是找不到最优子结构。今天那道接雨水给我整麻了。”……LeetCode 真的害了我室友!!!
老六f:编程嘉豪来了
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务