百万数据集测试赛题秒级查询的MySQL方案

news2024/11/27 10:42:17

目录

比赛题目

最佳解法

solution_row

prime_encoded 

相关知识

递归 CTE

SUBSTRING_INDEX

引用资料


比赛题目

有一张表 cards,id 是自增字段的数字主键,另外有4个字段 c1,c2,c3,c4 ,每个字段随机从 1~10 之间选择一个整数,要求选手使用一条 SQL 给出 24 点的计算公式,返回的内容示例如下图:

最佳解法

参赛数据库:MySQL

性能评测:百万级数据代码性能评测 0.67秒

综合得分:95

以下是代码说明思路简介:

0、 核心:因为4张牌计算24点时的顺序可任意互换,所以不同排列的4张牌可视为同一组合。采用质数编码,把1到10映射成2到29内的质数,4张牌的积可作为该组合的唯一编码

1、本地写代码,通过简单的回溯算法,生成24点游戏的所有解,按照152,((1+1)+1)*8,156,(6*2)*(1+1),...即"质数乘积:解决方案表达式" 的格式输出(质数表达式对应的质数在这步算好,而不放如mysql可以提高计算速度)

  • 生成4个1-10可重复的所有组合
  • 通过回溯减枝给定的4个数判断是否符合24点,核心思路可以参考力扣的679. 24 点游戏
  • 按照"质数乘积:解决方案表达式" 的格式整理输出 
import itertools

TARGET = 24
EPSILON = 1e-6
ADD, MULTIPLY, SUBTRACT, DIVIDE = 0, 1, 2, 3


def generate_expr(nums, current_exprs=None):
    if current_exprs is None:
        current_exprs = [(str(num), num) for num in nums]

    if len(current_exprs) == 1:
        _, value = current_exprs[0]
        if abs(value - TARGET) < EPSILON:
            return [current_exprs[0][0]]
        return []

    results = []
    size = len(current_exprs)
    for i in range(size):
        for j in range(size):
            if i != j:
                next_exprs = [current_exprs[k] for k in range(size) if k != i and k != j]
                for op in range(4):
                    if op < 2 and i > j:
                        continue

                    expr1, val1 = current_exprs[i]
                    expr2, val2 = current_exprs[j]
                    new_expr = ""

                    if op == ADD:
                        new_expr = f"({expr1}+{expr2})"
                        next_exprs.append((new_expr, val1 + val2))
                    elif op == MULTIPLY:
                        new_expr = f"({expr1}*{expr2})"
                        next_exprs.append((new_expr, val1 * val2))
                    elif op == SUBTRACT:
                        new_expr = f"({expr1}-{expr2})"
                        next_exprs.append((new_expr, val1 - val2))
                    elif op == DIVIDE:
                        if abs(val2) < EPSILON:
                            continue
                        new_expr = f"({expr1}/{expr2})"
                        next_exprs.append((new_expr, val1 / val2))

                    sub_results = generate_expr([], next_exprs)
                    for result in sub_results:
                        results.append(result)
                    next_exprs.pop()

    return results

def find_prime_factor_product(nums):

    #1-10分别映射如下字段
    prime_map = {index+1: prime for index, prime in enumerate([2, 3, 5, 7, 9, 11, 13, 17, 19, 23])}
    result = 1

    for num in nums:
          result = result * prime_map[num]

    return result
def eval_expr(expr):
    try:
        return abs(eval(expr) - 24) < 1e-6
    except ZeroDivisionError:
        return False


def find_expressions_for_24(nums):
    results = set()

    for p_nums in set(itertools.permutations(nums)):
        for expr in generate_expr(list(p_nums)):
            # 符合24点
            if eval_expr(expr):
                results.add(expr)
    return results


# Generate all combinations of 4 numbers from 1 to 10, without considering permutations
all_combinations = set(itertools.combinations_with_replacement(range(1, 11), 4))

# Find all expressions that result in 24 for each combination
expressions_resulting_in_24 = {}
for combo in all_combinations:
    prime_factors_product = find_prime_factor_product(combo)
    expressions = find_expressions_for_24(combo)
    if expressions:
        expressions_resulting_in_24[prime_factors_product] = expressions

# Display the results
for combo, exprs in list(expressions_resulting_in_24.items()):
    print(f"Combination {combo}:")
    for expr in exprs:
        print(f"  {expr}")
    print()

 打印结果如下:

Combination 486:
  (1-(2-(5*5)))
  ((1+(5*5))-2)
  (1+((5*5)-2))
  ((5*5)-(2-1))
  ((1-2)+(5*5))
  ((5*5)+(1-2))

Combination 5049:
  (8*(2+(6-5)))
  ((2-8)+(6*5))

.........

2、受限于代码大小10k限制,通过把上一步生成的数据进行压缩:SELECT REPLACE(TO_BASE64(COMPRESS('(4/1)*(3*2),2/(1/(4*3)),((3*4)*2)/1,...'))...')), '\n', '')

SELECT REPLACE(TO_BASE64(COMPRESS('(4/1)*(3*2),2/(1/(4*3)),((3*4)*2)/1,...')), '\n', '') AS compressed_base64;

3、提交的代码中,先对上一步生成的数据解压缩:UNCOMPRESS(FROM_BASE64('XXXX')),并通过递归CTE生成查询表:(4/1)*(3*2);2/(1/(4*3));((3*4)*2)/1,...'));...

SELECT UNCOMPRESS(FROM_BASE64('XXXX')) AS decompressed_data;

4、对输入表LEFT JOIN上一步生成的查询表,关联的键值是对c1,c2,c3,c4做质数编码后的积。

以下是如何在MySQL中使用CTE来分割由分号分隔的字符串的完整示例。假设solution_str是一个由分号分隔的24点游戏解的长字符串,每个解之间用分号分隔。 

-- 生成1到10的数字
WITH RECURSIVE number_list AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM number_list WHERE n < 10 
),
--prime_numbers 表包含一个映射,它将数字1到10映射到它们对应的质数
prime_numbers AS (
  SELECT n, ELT(n, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29) AS prime FROM number_list -- 映射1-10到质数
),
solution_set AS (
  SELECT CAST(UNCOMPRESS(FROM_BASE64('XXXX')) AS CHAR) AS solution_str -- 假设XXXX是压缩且编码后的字符串
),

--将24点计算表达式解决方案的长字符串分解为单独的行,每行一个解决方案,同时记录编号
solution_rows AS (
  SELECT 
    SUBSTRING_INDEX(SUBSTRING_INDEX(sub_solution.solution, ';', numbers.n), ';', -1) AS solution_pair,
    numbers.n + 1 AS next_n
  FROM solution_set
  JOIN (
    SELECT n FROM number_list
  ) AS numbers ON CHAR_LENGTH(solution_str) 
  - CHAR_LENGTH(REPLACE(solution_str, ';', '')) >= numbers.n - 1
),
split_solutions AS (
  SELECT 
    SUBSTRING_INDEX(solution_pair, ':', 1) AS prime_product,
    SUBSTRING_INDEX(solution_pair, ':', -1) AS solution_expression
  FROM solution_rows
),
prime_encoded AS (
  SELECT id, 
    (SELECT prime FROM prime_numbers WHERE n = c1) *
    (SELECT prime FROM prime_numbers WHERE n = c2) *
    (SELECT prime FROM prime_numbers WHERE n = c3) *
    (SELECT prime FROM prime_numbers WHERE n = c4) AS prime_product 
    --cards 表有多列,其中每列(c1, c2, c3, c4)都包含1到10之间的数字 
 FROM cards
)
SELECT c.*, s.solution
FROM prime_encoded AS c
LEFT JOIN solution_rows AS s ON c.prime_product = s.prime_product;

solution_row

可以理解为决方案的长字符串和num_list中不超过N+1的数字逐个关联

  • solution_str 是一个包含多个解决方案的长字符串,其中每个解决方案由分号分隔。

  • CHAR_LENGTH(solution_str) 计算solution_str的总字符数。

  • REPLACE(solution_str, ';', '')solution_str中的所有分号替换为空字符,从而移除所有分号。

  • CHAR_LENGTH(REPLACE(solution_str, ';', '')) 计算移除分号后的字符串长度。

  • CHAR_LENGTH(solution_str) - CHAR_LENGTH(REPLACE(solution_str, ';', '')) 这个表达式计算原始字符串和移除分号后字符串长度的差值。这个差值实际上就是原始字符串中分号的数量。因为每个分号被替换为一个空字符,每替换一个分号,长度就减少一个字符。

  • >= numbers.n - 1 这部分是用来确保当前数字(来自numbers CTE)不超过分号的数量加1。因为如果有N个分号,那么就有N+1个解决方案。

prime_encoded 

card表的每个字段添加对应的质数字段

  • 每次SELECT prime FROM prime_numbers WHERE n = c1(以及对于c2, c3, c4)的子查询都会返回c1(以及c2, c3, c4)对应的质数。然后将这些质数相乘,生成一个唯一的prime_product,它代表了该行的四个数字的一个唯一编码。

  • 最终,prime_encoded CTE返回两列:原始表cardsid和计算出的prime_product

相关知识

递归 CTE

在MySQL中,CTE(公用表表达式)的支持开始于8.0版本。

-- 生成1到10的数字
WITH RECURSIVE number_list AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM number_list WHERE n < 10 
),
  • WITH RECURSIVE: 这是定义递归CTE的开始。使用RECURSIVE关键字来表明接下来定义的CTE将是递归的。
  • number_list AS: 这是新定义的递归CTE的名称,number_list

  • (SELECT 1 AS n: 这是CTE的基础案例或种子查询,它返回第一个值,即数字1。AS n表示返回的列的名称。

  • UNION ALL: 用来合并多个查询结果,在本例中合并种子查询和递归部分。UNION ALL会包含所有的合并结果,甚至包括重复项。与简单的UNION相比,UNION ALL效率更高。

  • SELECT n + 1 FROM number_list WHERE n < 10: 这是递归部分的查询。它从number_list CTE中选出当前的n,加1后再返回。WHERE n < 10是递归的结束条件,即当生成的数字达到10时,不再进行递归。 

SUBSTRING_INDEX

SUBSTRING_INDEX(stringdelimiternumber)

number如果是正数,则此函数返回从左到右第number个分隔符之前的所有值。

number如果是负数,则此函数返回从右到左第number个分隔符之后的所有值。

-- 获取直到第3个分隔符之前的内容
SELECT SUBSTRING_INDEX('1;2;3;4', ';', 3);

-- 获取倒数第一个分隔符之后的内容
SELECT SUBSTRING_INDEX('1;2;3;4', ';', -1);

为了精确获取第3项,你需要两个SUBSTRING_INDEX函数的嵌套调用: 

-- 获取第3项
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('1;2;3;4', ';', 3), ';', -1);

引用资料

2023数据库编程大赛-答辩总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1342464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十二:爬虫-Scrapy框架(上)

一&#xff1a;Scrapy介绍 1.Scrapy是什么&#xff1f; Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架(异步爬虫框架) 通常我们可以很简单的通过 Scrapy 框架实现一个爬虫&#xff0c;抓取指定网站的内容或图片 Scrapy使用了Twisted异步网…

多平面包络的圆柱体参数估计

多平面包络的圆柱体参数估计 场景 现有多个空间平面包络一个柱体&#xff0c;从圆柱顶端俯视如图所示&#xff1a; 中心位置为圆柱实际所在位置。现在已知这些平面的参数&#xff08;每个平面的方程均为axbyczd0形式, 参数为a,b,c,d&#xff09;&#xff0c;希望求解它们包络…

阿里云oss无法访问.apk或者.ipa的文件

-- 有意栽花花不发 无心插柳柳成荫 0048-00000201 更新时间&#xff1a;2023-07-19 10:31:16 问题描述 在2023年08月15日后为Bucket开通传输加速&#xff0c;如果通过OSS传输加速域名访问其中后缀为.apk或者.ipa的文件&#xff0c;服务器返回400错误。 问题原因 出于安全…

分布式IO在工业自动化中的应用

传统的自动化产线及物流系统主要是利用PLC来处理数据&#xff0c;并将这些数据保存在PC当中。但是随着互联网技术的迅速发展&#xff0c;越来越多的系统集成商利用分布式IO模块&#xff0c;实现从控制器到自动化最底层之间的IO通信。 分布式IO在工业自动化中的应用 分布式IO是用…

再次被gpt震撼到了,md转json

1.md内容来自excel 参考链接&#xff1a; https://chat.xutongbao.top/

什么是计算机视觉

计算机视觉&#xff08;Computer Vision&#xff09;是一门研究如何让计算机能够理解和分析数字图像或视频的学科。简单来说&#xff0c;计算机视觉的目标是让计算机能够像人类一样对视觉信息进行处理和理解。为实现这个目标&#xff0c;计算机视觉结合了图像处理、机器学习、模…

低代码平台搭建ERP系统 低代码快速开发灵活的ERP

随着数字化时代的到来&#xff0c;企业迫切需要高效、灵活的ERP系统来提高运营效率。在这一背景下&#xff0c;白码低代码平台成为了企业实现数字化转型的首选工具。本文将介绍低代码开发ERP的概念&#xff0c;并以白码低代码平台为例&#xff0c;探讨其在企业数字化转型中的重…

解决jenkins、git拉取代码仓库失败Please make sure you have the correct access rights

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

spellman高压发生器电源维修XRV450PN4500 NY1059

Spellman高压电源X射线发生器维修XRV系列常见维修型号&#xff1a;XRV160N1800, XRV160N3000, XRV160P4000, XRV160P6000/208V 3o, XRV225N3000, XRV225N6000/208V 3o, XRV225P4000, XRV350PN4500, XRV450PN4500。 Spellman所拥有的变频器架构可以使高压电源获得高利用率的效率…

小C说历史(人物介绍第二篇):Unix之父 C语言之父 伟大的Ken Thompson 肯·汤普森

Unix之父 C语言之父 伟大的Ken Thompson 肯汤普森 Unix之父——肯•汤普森&#xff08;Ken Thompson&#xff09;被称作“世界上最杰出的程序员”&#xff0c;他自学编程&#xff0c;26岁创造Unix&#xff0c;改写了计算机操作系统的历史&#xff0c;并在古稀之年成为Go语言的共…

win10 telnet服务开启教程

win10 telnet服务开启教程 1、打开控制面板&#xff0c;选择【程序和功能】 2、点击【启用或关闭Windows功能】 3、勾选【Telnet 客户端】,然后点击确定。

【译文】IEEE白皮书 6G 太赫兹技术的基本原理 2023版

第一章 简介 太赫兹波是介于微波和光波之间的光谱区域&#xff0c;频率从 0.1THz ~ 10THz 之间&#xff0c;波长在 3mm ~ 30μm 之间。提供大块连续的频带范围以满足对 Tbit/s 内极高数据传输速率的需求&#xff0c;使该区域成为下一代无线通信&#xff08;6G&#xff09;的重…

外汇天眼:Valdas Dapkus和Tradewale因零售外汇欺诈计划被判支付280万美元

美国衍生品市场监管机构商品期货交易委员会&#xff08;CFTC&#xff09;宣布&#xff0c;美国新泽西地区法院于11月28日发布了对位于伊利诺伊州的Valdas Dapkus的最终裁定默认令。5月4日&#xff0c;法院对Dapkus控制的两家实体——Tradewale LLC和Tradewale Managed Fund发布…

电子工程师如何接私活赚外快?

对电子工程师来说&#xff0c;利用业余时间接私活是个很常见的技术&#xff0c;不仅可以赚取额外收入&#xff0c;也能提升巩固技术&#xff0c;可以说国内十个工程师&#xff0c;必有五个在接私活养家糊口&#xff0c;如果第一次接私活&#xff0c;该如何做&#xff1f; 很多工…

虚拟机迁移技术原理与应用

虚拟机迁移技术主要应用于两种场景&#xff1a; 第一种&#xff0c;随着现在虚拟化的发展&#xff0c;传统it架构的物理机需迁移到虚拟机上&#xff0c;实现负载均衡、资源优化等目的。 第二种&#xff0c;将虚拟机从一个虚拟化平台迁移到另一个虚拟化平台&#xff0c;可以是…

Django 文件上传(十二)

当 Django 处理文件上传时&#xff0c;文件数据最终会被放置在 request.FILES 。 查看文档&#xff1a;文件上传 | Django 文档 | Django Django工程如下&#xff1a; 创建本地存储目录 在static/应用目录下创建uploads目录用于存储接收上传的文件 在settings.py 配置静态目…

Android Context在四大组件及Application中的表现

文章目录 Android Context在四大组件及Application中的表现Context是什么Context源码Activity流程分析Service流程分析BroadcastReceiver流程分析ContentProvider流程分析Application流程分析 Android Context在四大组件及Application中的表现 Context是什么 Context可以理解…

Python-动态柱状图可视化

柱状图 1.基础柱状图1.1通过Bar构建基础柱状图1.2反转x轴&#xff0c;y轴1.3数值标签在右侧1.4总结 2.基础时间柱状图2.1掌握基础的时间线配置动态图表2.2创建时间线2.3自动播放2.4时间线设置主题2.5总结 3.GDP动态柱状图绘制3.1掌握列表的sort方法并配合配合lambda匿名函数完成…

NAS上使用docker+postgresql搭建私有云笔记joplin全终端适配

文章目录 前置条件步骤1&#xff1a;获取joplin的镜像步骤2&#xff1a;配置容器参数2.1 端口设置2.2环境变量设置&#xff08;配置数据库&#xff09; 步骤3. 启动服务端步骤4. 配置客户端4.1 下载客户端4.2 配置客户端同步 步骤5. 外网访问插件安装 通常我们都会用到印象笔记…

代码随想录刷题笔记(DAY2)

今日总结&#xff1a;今天在学 vue 做项目&#xff0c;学校还有很多作业要完成&#xff0c;熬到现在写完了三道题&#xff0c;有点太晚了&#xff0c;最后一道题的题解明天早起补上。&#xff08;补上了&#xff09; Day 2 01. 有序数组的平方&#xff08;No. 977&#xff09;…