SQL进阶技巧:如何计算算法题分发糖果问题?

目录

[0 问题描述](#0 问题描述)

[1 数据准备](#1 数据准备)

[2 问题分析](#2 问题分析)

[3 小结](#3 小结)

专栏优势:(1)一次收费持续更新。


0 问题描述

n 个孩子站成一排,每个孩子都有一个评分值(整数),你需要按照以下要求给这些孩子分发糖果:

  1. 每个孩子至少分配到 1 颗糖果。
  2. 评分更高的孩子必须比他左右两边评分低的孩子获得更多的糖果(如果有的话)。
  3. 求最少需要多少颗糖果来满足上述条件。

例如,给定孩子的评分数组为 [1, 0, 2],那么最少需要的糖果数是 5(分别给这三个孩子分配 212 颗糖果)。

1 数据准备

sql 复制代码
-- 创建 kids_rating 表
CREATE TABLE kids_rating (
    kid_id INT,
    rating INT
);

-- 插入示例数据
INSERT INTO kids_rating VALUES
(1, 1),
(2, 0),
(3, 2);

2 问题分析

可以通过两次遍历数组(在 SQL 中模拟这个过程)来解决这个问题。

第一次遍历(从左到右)

  • 初始化每个孩子的糖果数为 1
  • 从左到右遍历,如果当前孩子的评分大于左边孩子的评分,那么当前孩子的糖果数应该比左边孩子多 1(满足评分高的孩子糖果更多的条件)。

第二次遍历(从右到左)

  • 再次检查每个孩子的糖果数,从右到左遍历,如果当前孩子的评分大于右边孩子的评分,并且当前孩子的糖果数小于等于右边孩子的糖果数(说明之前从左到右分配时可能没满足条件),那么需要更新当前孩子的糖果数为右边孩子的糖果数加 1

最后统计糖果总数

  • 对所有孩子最终分配的糖果数进行求和,得到最少需要的糖果总数。

第一步:添加序号列并展示(模拟从左到右顺序,类似数组索引)

sql 复制代码
-- 使用窗口函数添加序号列,方便后续按顺序处理数据,展示中间结果
WITH RankedKids AS (
    SELECT
        kid_id,
        rating,
        ROW_NUMBER() OVER (ORDER BY kid_id) AS seq_num
    FROM
        kids_rating
)
SELECT
    kid_id,
    rating,
    seq_num
FROM
    RankedKids;
kid_id rating seq_num
1 1 1
2 0 2
3 2 3

第二步:结合左右遍历情况计算糖果数

sql 复制代码
-- 结合从左到右和从右到左遍历情况,一次性计算糖果数,展示中间结果
WITH RankedKids AS (
    SELECT
        kid_id,
        rating,
        ROW_NUMBER() OVER (ORDER BY kid_id) AS seq_num
    FROM
        kids_rating
),
CandyDistribution AS (
    SELECT
        rk.kid_id,
        rk.rating,
        MAX(
            CASE
                WHEN rk.rating > LAG(rk.rating, 1, rk.rating) OVER (ORDER BY rk.seq_num) THEN LAG(candy, 1, 1) OVER (ORDER BY rk.seq_num) + 1
                WHEN rk.rating > LEAD(rk.rating, 1, rk.rating) OVER (ORDER BY rk.seq_num DESC) THEN LEAD(candy, 1, 1) OVER (ORDER BY rk.seq_num DESC) + 1
                ELSE 1
            END
        ) AS candy
    FROM (
        SELECT
            kid_id,
            rating,
            seq_num,
            1 AS candy
        FROM
            RankedKids
    ) rk
    GROUP BY
        rk.kid_id,
        rk.rating,
        rk.seq_num
)
SELECT
    kid_id,
    rating,
    candy
FROM
    CandyDistribution;
kid_id rating candy
1 1 2
2 0 1
3 2 2

这里在 CandyDistribution CTE 中,通过在 MAX 函数里嵌套 CASE WHEN 语句,把从左到右(使用 LAG 函数判断左边孩子情况)和从右到左(使用 LEAD 函数判断右边孩子情况)的糖果数更新逻辑合并在一起了。对于每个孩子,取满足条件的糖果数中的最大值(因为要同时满足左右两边比较的规则),初始时每个孩子糖果数设为 1。这样就简化了之前分两次更新糖果数的操作,一次计算就得出相对合理的每个孩子的糖果数情况。

第三步:统计最少需要的糖果总数(最终结果)

sql 复制代码
-- 统计最少需要的糖果总数,最终结果
WITH RankedKids AS (
    SELECT
        kid_id,
        rating,
        ROW_NUMBER() OVER (ORDER BY kid_id) AS seq_num
    FROM
        kids_rating
),
CandyDistribution AS (
    SELECT
        rk.kid_id,
        rk.rating,
        MAX(
            CASE
                WHEN rk.rating > LAG(rk.rating, 1, rk.rating) OVER (ORDER BY rk.seq_num) THEN LAG(candy, 1, 1) OVER (ORDER BY rk.seq_num) + 1
                WHEN rk.rating > LEAD(rk.rating, 1, rk.rating) OVER (ORDER BY rk.seq_num DESC) THEN LEAD(candy, 1, 1) OVER (ORDER BY rk.seq_num DESC) + 1
                ELSE 1
            END
        ) AS candy
    FROM (
        SELECT
            kid_id,
            rating,
            seq_num,
            1 AS candy
        FROM
            RankedKids
    ) rk
    GROUP BY
        rk.kid_id,
        rk.rating,
        rk.seq_num
)
SELECT
    SUM(candy) AS total_candy
FROM
    CandyDistribution;
total_candy
5

3 小结

文章利用SQL模拟常规的双遍历更新逻辑完整地解决了 "分发糖果" 问题,整体思路依然是先从左到右遍历更新一次糖果数,再从右到左遍历更新一次糖果数,最后统计糖果总数,只不过借助窗口聚合函数来更方便地实现相关逻辑。

如果您觉得本文还不错,对你有帮助,那么不妨可以关注一下我的数字化建设实践之路专栏,这里的内容会更精彩。

专栏 原价99,现在活动价59.9,按照阶梯式增长,还差5个人上升到69.9,最终恢复到原价

专栏优势:

(1)一次收费持续更新。

(2)实战中总结的SQL技巧,帮助SQLBOY 在SQL语言上有质的飞越,无论你应对业务难题及面试都会游刃有余【全网唯一讲SQL实战技巧,方法独特】

SQL很简单,可你却写不好?每天一点点,收获不止一点点-CSDN博客

(3)实战中数仓建模技巧总结,让你认识不一样的数仓。【数据建模+业务建模,不一样的认知体系】(如果只懂数据建模而不懂业务建模,数仓体系认知是不全面的

(4)数字化建设当中遇到难题解决思路及问题思考。

我的专栏具体链接如下

数字化建设通关指南_莫叫石榴姐的博客-CSDN博客

相关推荐
Feng_Ye7几秒前
数据结构泛谈
数据结构
重生之Java开发工程师8 分钟前
ArrayList与LinkedList、Vector的区别
java·数据结构·算法·面试
见未见过的风景10 分钟前
将三个list往一个excel表的三个sheet中写入,能用多线程提高写入速度
数据结构·list·excel
开心工作室_kaic25 分钟前
springboot460实习生管理系统设计和实现(论文+源码)_kaic
运维·服务器·前端·数据库·vue.js
Wils0nEdwards30 分钟前
Leetcode 串联所有单词的子串
java·算法·leetcode
上山的月31 分钟前
MySQL通用语法 -DDL、DML、DQL、DCL
数据库·mysql
zybishe32 分钟前
免费送源码:Java+ssm++MVC+HTML+CSS+MySQL springboot 社区医院信息管理系统的设计与实现 计算机毕业设计原创定制
java·hadoop·sql·zookeeper·html·json·mvc
Y编程小白41 分钟前
Git版本控制工具--基础命令和分支管理
大数据·git·elasticsearch
埃菲尔铁塔_CV算法44 分钟前
新型滤波算法在信号处理中的创新与应用
算法·信号处理
toto4121 小时前
Java中的锁机制 与 synchronized的理解
java·算法