传说中 6 个月都未必能全解开的 3 道 SQL 题,来挑战下?
点击蓝色“有关SQL”关注我哟
加个“星标”,天天与6000人一起快乐成长
1年多过去了,这三道SQL题,有人解出来了么?
你也来试试
这 3 道巨难的题目,来自 itpub 的 SQL 数据库编程大赛。说起 itpub 就不得不说它与 Oracle 的渊源,多少大师都在这里诞生。想成为 SQL 大师,有个最快的方法,就是刷题。如果能刷遍这里的题,Oracle 工作,十拿九稳。当年支付宝首席数据库架构师冯大-冯春培,就是典范。
好了,闲话不说,上题!
1,5X5方格棋盘难题
在5X5的方格棋盘中(如图),每行、列、斜线(斜线不仅仅包括对角线)最多可以放两个球,如何摆放才能放置最多的球,这样的摆法总共有几种?输出所有的摆法。
要求:用一句SQL实现。
输出格式:
从方格棋盘第一行至第5行,每行从第一列到第5列依次输出,0表示不放球,1表示放球。
例如:
1001000000000000000000000。
一行输出一个行号和一个解,按解所在的列字符串顺序从大到小排序。
详情:http://www.itpub.net/thread-1400067-1-1.html 答案:http://www.itpub.net/thread-1407072-1-1.html 我想说:尽量自己做,否则即使看了答案,对提高技能也无帮助
难理解的是,最长的对角线上也不能有 3 个 1
2,挖地雷之标出有地雷的格子
在M*N的矩阵中,单元格中的数字表示该单元格周围地雷的数目,有数字的单元格肯定不是地雷。其余的单元格要么是地雷,要么是空位而且四周都没有地雷。
周围的定义为紧挨着的单元格,例如:
若单元格在矩阵的内部,则周围有8个单元格,如图a所示
若单元格在矩阵的四边,则周围有5个单元格,如图b所示
若单元格在矩阵的四角,则周围有3个单元格,如图c所示
输入输出格式:
用3个变量v_height、v_width、v_cnt表示雷区的长度、宽度和地雷个数,其中v_height、v_width均为大于0且小于32的整数,v_cnt为大于0且小于或等于v_height*v_width的整数。
var v_width NUMBER;
EXEC :v_width := 4;
var v_height NUMBER;
EXEC :v_height := 4;
var v_cnt NUMBER;
EXEC :v_cnt := 3;
用1个字符串变量表示从矩阵第一行至最后一行,每行从第一列到最后一列依次输出
如矩阵(为明显起见,用下划线表示空格,实际做题的输入输出仍用空格)
1 1 1 _
2 * 1 _
3 2 1
1 2 * 1
的字符串表示为:
VAR v_str VARCHAR2(1000);
exec :v_str :='111 2 1 32112 1'
正题 1):挖地雷之标出有地雷的格子
题目要求:用一句SQL实现
有若干地雷分布在图中,它们都有*标记,请把矩阵中的数字标出来。
如输入字符串为:
VAR v_str VARCHAR2(1000);
exec :v_str :=' * * * '
输出格式:在输入字符串中有地雷的位置保留'*',同时对它周围的单元格标上地雷数,若单元格周围没有地雷,则保持空格,对上述输入,则输出:
111 2*1 *32112*1
正题 2):挖地雷之标出有地雷的格子
题目要求:用一句SQL实现或用一个PL/SQL函数实现。
(如果用PL/SQL实现,则函数必须为
create or replace function
winmine(p_str varchar2
,p_width NUMBER
,p_height NUMBER
,p_cnt NUMBER)
return varchar2
as
begin...
return ...;
end;/
结果在sqlplus用
select winmine(:v_str,:v_width,:v_height,:v_cnt) from dual;
输出
如果有相应授权需要把grant语句一并给出,用户名为scott)
有C个地雷分布在图中,根据输入字符串提供的格子周围地雷数,把所有埋了地雷的格子标出来。
如输入字符串为:
VAR v_str VARCHAR2(1000);
exec :v_str :='111 2 1 32112 1'
输入地雷数为:
var v_cnt NUMBER;
EXEC :v_cnt := 3;
输出格式:在输入字符串中有地雷的位置标上'*',同时保留它周围的单元格标的地雷数,若单元格周围没有地雷,则保持空格,对上述输入,则输出:
111 2*1 *32112*1
本题不需要考虑错误处理,如果输入错误(比如地雷数输入变量和实际不符、雷区不是矩形、字符串中标的地雷数字错误),就允许任何输出。
数据库平台:Oracle 11g R2 版本(不能用12c,因为它有在sql语句中编写自定义函数功能)
详情:http://www.itpub.net/thread-1825024-1-1.html
3,井字棋
两个玩家,一个打圈(O),一个打叉(X),轮流在3乘3的井字格上打自己的符号,最先以任意一行、一列或对角线连成一线则为胜。规定X先手。
一个终局棋谱(MOVES)指的是从开始下子到一方获胜或者下完9个子出现平局,从头到尾的下子情况。一方获胜后,本局即终止。不得提前认输。
格子从上到下,从左到右,依次编号1-9
MOVES的第一位表示第一子位置,第二位表示第二子位置,......如果一方获胜,MOVES的长度有可能<9。
局面(BOARD)表示棋盘上呈现的局面,也是按照从上到下,从左到右排列。用X和0填入相应的格子。减号“-” 表示空位。
这里有个棋局:
表示出来是:
MOVES=3175968,
BOARD=O-X-OOXXX,
WINNER=X
第一题 :求出所有可能终局棋谱和相应的局面,插入如下的表中:
CREATE TABLE TICTACTOE (MOVES VARCHAR2(9) PRIMARY KEY,BOARDVARCHAR2(9),WINNER VARCHAR2(1));
格式要求:
首先CREATE 上述TICTACTOE表。然后用一个能直接放在“insert into TICTACTOE ”后面成功运行的SQL查询语句,一次性插入所有满足标准的棋谱和相应的局面、胜者(WINNER=X或O或D,其中D表示平局)
注意:本题要求生成所有可能的终局棋谱,只要符合规则即可,哪怕其中有些走法可能看起来很愚蠢,也得包含进去。还没下完的棋谱不要列入。
如果两个终局的局面(BOARD)相同,但是其下子顺序(MOVES)不同,则视为不同棋谱,两个都必须出现在结果中。
如果两个棋谱的MOVES不同,但是其终局局面(BOARD)经过旋转、翻转后重合,仍然被视为不同棋谱,两个都必须出现在结果中。
第二题:给定一个局面,假定该局面一定为有效(不会出现一方比另一方多两子的情况,或者两方都有三子连线的情况),用SQL判断出哪一方有必胜策略,以及获胜方最多再下几子必定会获胜。比如输入:V_BOARD='X-0------' 则输出'X3',表示WINNER=X,下子数=3,因为不管对手怎么走,X最多再下3子一定获胜。(不计入O再下的子数)
如果O方有失误,也有可能X再下两子就取胜的;X方也有可能下错而输掉,但这些都不在本题考虑范围,假定双方都是完美棋手,即双方都尽可能取胜,不能取胜则尽可能求和,不能求和则尽可能多下几子。
如果给定的局面中一方已经获胜,则输出获胜方符号和子数0,例如输入:V_BOARD='OXX—XOOX', 则输出'X0'
如果不存在必胜策略(比如一个空局:V_BOARD='---------'),则输出'D'。
输出中都不含单引号。
格式要求:
首先在sqlplus中声明变量var v_BOARDvarchar2(9),再对变量赋值(如:exec :v_BOARD:='X-O------')。然后用一个包含变量v_BOARD的查询语句,返回对应此棋局的结果字符串(X数字,或O数字,或D表示平局)
第三题:m,n,k游戏是指两个对手在m*n的棋盘上轮流下子,谁先在纵、横、四十五度斜线上连续取得k个子就获胜的一种游戏,井字棋游戏其实就是3,3,3的一种特例。五子棋则为15,15,5游戏。
上述按第二题的要求,使得SQL能够适用于m,n,k大于等于3的情况 。
详情:http://www.itpub.net/thread-1943911-1-1.html
完