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

目录

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

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

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

[3 小结](#3 小结)

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


0 问题描述

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

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

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

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博客

相关推荐
初心未改HD4 分钟前
DSH Skill开发实战:SKILL.md是给LLM看的操作手册,不是给人看的README,踩了4个坑
java·大数据·开发语言
程序 代码狂人12 分钟前
据仓库常见表类型详解(面试完整版,金融数仓适用)
大数据
Tairitsu_H25 分钟前
[动态规划#1] 子数组 | 最大子数组和 | 环形子数组的最大和 | 乘积最大子数组 | 乘积为正数的最长子数组
算法·动态规划
阿里云大数据AI技术31 分钟前
云栖实录|Hologres 5.0全新发布:Agent Native 的全模态实时数仓
大数据·人工智能·agent
笃行3501 小时前
列存储这条线,我顺着 KingbaseES 的文档摸了一遍
数据库
凯瑟琳.奥古斯特1 小时前
动态调优IoU提升OCR文本合并精度
开发语言·python·算法
小天源1 小时前
品牌 AI 智能监测与自动化采集系统
大数据·人工智能·自动化
Navicat中国1 小时前
Navicat 18 支持 Azure OpenAI 接入,合规 AI 赋能 SQL 开发
数据库·人工智能·microsoft·ai·azure·navicat·数据
1024奇点1 小时前
【仓颉语言入门 · 第二篇 第 10 课】
开发语言·数据库·ide·mysql·开源
布莱克6051 小时前
A* 算法详解:从原理到实现
开发语言·c++·算法