6

假设给你一个密码算术难题:

发送 + 更多 = 金钱

目标是用数字 (0-9) 代替字母,以便加法有效。

我了解如何在数学上解决这个问题,但我不确定如何使用关系数据库来解决这个问题。

如何设计模式来解决这个问题?

尝试解决此问题的 SQL 查询看起来如何?

编辑: 有一些限制:

  1. 给定的字母应始终使用相同的数字。例如,如果您猜测字母 E 是“5”,那么 E 应该在它出现的所有位置都得到值“5”。
  2. 不同的字母应该有不同的数字,例如,您不能将“4”分配给 E 和 M。
  3. 所有数字(单词)都不能有任何前导零
4

2 回答 2

7

这回答了用户提出的另一个问题。

SEND + MORE = MONEY,其中每个字符都有一个唯一的数字,并且没有单词以零开头。

select
    top 1
    S.num as S,
    E.num as E,
    N.num as N,
    D.num as D,
    M.num as M,
    O.num as O,
    R.num as R,
    Y.num as Y,
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num) as [SEND],
    (M.num * 1000 + O.num * 100 + R.num * 10 + E.num) as MORE,
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num) + (M.num * 1000 + O.num * 100 + R.num * 10 + E.num) as SEND_plus_MORE,
    (M.num * 10000 + O.num * 1000 + N.num * 100 + E.num * 10 + Y.num) as [MONEY]

from
    Digits as S
    join digits as E on E.num <> S.num
    join digits as N on N.num <> S.num and N.num <> E.num
    join digits as D on D.num <> S.num and D.num <> E.num and D.num <> N.num
    join digits as M on M.num <> S.num and M.num <> E.num and M.num <> N.num and M.num <> D.num
    join digits as O on O.num <> S.num and O.num <> E.num and O.num <> N.num and O.num <> D.num and O.num <> M.num
    join digits as R on R.num <> S.num and R.num <> E.num and R.num <> N.num and R.num <> D.num and R.num <> M.num and R.num <> O.num
    join digits as Y on Y.num <> S.num and Y.num <> E.num and Y.num <> N.num and Y.num <> D.num and Y.num <> M.num and Y.num <> O.num and Y.num <> R.num

where
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num)
    + (M.num * 1000 + O.num * 100 + R.num * 10 + E.num)
    = (M.num * 10000 + O.num * 1000 + N.num * 100 + E.num * 10 + Y.num)     
    and S.num <> 0 and M.num <> 0

我在 WHERE 子句中考虑了一些东西来强制执行唯一数字,但我相信这最终会在检查 WHERE 子句之前处理太多的排列。

由于我们只处理最多 10 位数字,我认为最好构建长 ON 子句来代替速度问题。

这是没有疯狂的 ON 子句的 FROM + WHERE 子句。这在我的服务器上运行得慢了很多。

from
    Digits as S
    cross join digits as E
    cross join digits as N
    cross join digits as D
    cross join digits as M
    cross join digits as O
    cross join digits as R
    cross join digits as Y

where
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num)
    + (M.num * 1000 + O.num * 100 + R.num * 10 + E.num)
    = (M.num * 10000 + O.num * 1000 + N.num * 100 + E.num * 10 + Y.num)     
    and S.num <> 0 and M.num <> 0

        and (select max(B.Count) from   
                (select COUNT(*) as Count from 
                    (select S.num, 's' as letter   -- the letters are included to make sure the unions do not merge equivalent rows
                    UNION select E.num, 'e'
                    UNION select N.num, 'n'
                    UNION select D.num, 'd'
                    UNION select M.num, 'm'
                    UNION select O.num, 'o'
                    UNION select R.num, 'r'
                    UNION select Y.num, 'y') as A
                    group by A.num
                ) as B
             ) = 1
于 2013-02-27T05:30:44.370 回答
5

作者提出了两个截然不同的问题。

这回答了提出的问题,OVER + FLOW = STACK,其中每个字符不一定有唯一的数字,可能涉及超过 10 个字符

  • 有一个规定,每个字符都有一个唯一的数字,但是对于 OVER + FLOW + STACK 是不可能的,因为有太多的字母。

Digits当表包含一列,其中每条记录包含 1 到 9 之间的整数(或 0 到 9,如果您愿意),这样的事情可能会起作用。

交叉连接在性能方面非常讨厌,但这可能是一个起点。

select
    top 5 
    O.num as O,
    V.num as V,
    E.num as E,
    R.num as R,
    F.num as F,
    L.num as L,
    W.num as W,
    S.num as S,
    T.num as T,
    A.num as A,
    C.num as C,
    K.num as K,
    (O.num * 1000 + V.num * 100 + E.num * 10 + R.num) as [OVER],
    (F.num * 1000 + L.num * 100 + O.num * 10 + W.num) as FLOW,
    (O.num * 1000 + V.num * 100 + E.num * 10 + R.num) + (F.num * 1000 + L.num * 100 + O.num * 10 + W.num) as OVER_plus_FLOW,
    (S.num * 10000 + T.num * 1000 + A.num * 100 + C.num * 10 + K.num) as STACK
from
    Digits as O
    cross join digits as V
    cross join digits as E
    cross join digits as R
    cross join digits as F
    cross join digits as L
    cross join digits as W
    cross join digits as S
    cross join digits as T
    cross join digits as A
    cross join digits as C
    cross join digits as K
where
    (O.num * 1000 + V.num * 100 + E.num * 10 + R.num)
    + (F.num * 1000 + L.num * 100 + O.num * 10 + W.num)
    = (S.num * 10000 + T.num * 1000 + A.num * 100 + C.num * 10 + K.num)

根据我对问题的理解,有多种解决方案。这是此代码找到的前 5 个:

在此处输入图像描述

我删除了 0,因为您可以用零替换每个字母并获得便宜的答案(基于您最初的问题修订)。

这是唯一的表Digits

在此处输入图像描述

于 2013-02-27T04:46:23.077 回答