我想编写一个函数,使用以下一组规则从标准电话键盘(图1)生成所有可能的数字:
-
电话号码以数字2开头
-
电话号码长10位
当骑士在国际象棋中移动时,选择每个电话号码中的 -
个连续数字
在国际象棋中,骑士(有时称为马)垂直移动两步,水平移动一步或水平移动两步,垂直移动一步 .
在电话号码中只能使用数字 - 即不允许使用(#)和(*)键 .
该功能必须将电话号码和初始位置的长度作为输入,并且输出给出唯一电话号码的数量 .
我是一个新手,面临构建逻辑的困难 . 我试着这样做,这绝对不是一个正确的方法 .
def genNumbers(len, initpos):
numb = list('2xxxxxxxxx')
#index 1
numb[1] = 7 or 9
if numb[1] == 7:
numb[2] == 2 or 6
elif numb[1] == 9:
numb[2] == 2 or 4
#index 2
if numb[2]== 2:
numb[3] == 7 or 9
elif numb[2]== 4:
numb[3] == 3 or 9
elif numb[2]== 6:
numb[3] == 1 or 7
#index 3
if numb[3]== 1:
numb[4] == 6 or 8
elif numb[3]== 3:
numb[4] == 4 or 8
elif numb[3]== 7:
numb[4] == 2 or 6
elif numb[3]== 9:
numb[4] == 2 or 4
#index 4
if numb[4] == 8:
numb[5]== 1 or 3
elif numb[4] == 2:
numb[5]== 7 or 9
elif numb[4] == 4:
numb[5]== 3 or 9
elif numb[4] == 6:
numb[5]== 1 or 7
#index 5
if numb[5] == 1:
numb[6]== 6 or 8
elif numb[5] == 3:
numb[6]== 4 or 8
elif numb[5] == 7:
numb[6]== 2 or 6
elif numb[5] == 9:
numb[6]== 2 or 4
#index 6
if numb[6] == 2:
numb[7]== 7 or 9
elif numb[6] == 4:
numb[7]== 3 or 9
elif numb[6] == 6:
numb[7]== 1 or 7
elif numb[6] == 8:
numb[7]== 1 or 3
#index 7
if numb[7] == 1:
numb[8]== 6 or 8
elif numb[7] == 3:
numb[8]== 4 or 8
elif numb[7] == 7:
numb[8]== 2 or 6
elif numb[7] == 9:
numb[8]== 2 or 4
#index 8
if numb[8] == 6:
numb[9]== 1 or 7
elif numb[8] == 8:
numb[9]== 1 or 3
elif numb[8] == 4:
numb[9]== 3 or 9
elif numb[8] == 2:
numb[9]== 7 or 9
return numb
任何帮助将非常感谢!
2 回答
序曲
让我们说另一种解决你的问题的方法,它不涉及线性代数,但仍然依赖于图论 .
代表
您的问题的自然表示是图表,如下所示:
并相当于:
我们可以用字典来表示这个图:
这种结构将使您无需编写
if
语句 .邻接矩阵
上面的表示包含与邻接矩阵相同的信息 . 此外,我们可以从上面的结构生成它(将布尔稀疏矩阵转换为积分矩阵):
其中
A
是another answer中定义的邻接矩阵 .递归
现在我们可以使用递归生成所有电话号码:
然后我们 Build 电话号码列表:
它返回:
现在它只是采取列表的长度:
检查
我们可以检查没有重复:
我们可以查看我们在这个版本中仍然保留的另一个答案的最后一位数的观察结果:
电话号码不能以:
比较
第二个答案:
不需要
numpy
(不需要线性代数),它只使用Python标准库;使用图表表示,因为它是您问题的自然表示;
在计算之前生成所有电话号码,之前的答案没有生成所有电话号码,我们只有
x********y
表格中的号码详细信息;使用递归,而不仅仅是迭代,来解决问题;
这个函数的复杂性似乎是指数级的,如果我们不需要生成电话号码,我们应该使用Matrix Power版本 .
基准
Claim without proof: 递归函数的复杂性应该在
O(2^n)
和O(3^n)
之间,因为递归树作为n-1
的深度,每个内部节点创建最少2条边和最多3条边 . 这里的方法不是分而治之的组合字符串生成器 .对两个函数进行基准测试似乎证实了这一主张:
递归函数以对数标度显示线性行为,其确认了指数复杂性并且如所述限制 . 更糟糕的是,除了计算之外,还需要越来越多的内存来存储列表(我无法获得比_27390更多的内容,然后我的笔记本电脑冻结了) .
对于问题大小
n
,Matrix Power方法似乎有一个恒定的时间 . numpy.linalg.matrix_power上没有实现细节,但这是known eigenvalues problem . 因此,复杂性似乎在n
之前是恒定的,因为矩阵形状独立于n
(它仍然是10x10
矩阵)并且大部分计算时间即将解决特征值问题而不是将对角矩阵提升为n
th幂 . 该解决方案将需要准恒定量的存储器来存储矩阵及其分解,仅此而已 .功能签名
关键理念
您的问题可以通过图论和线性代数来解决(这些学科遇到的一个有趣的地方是离散数学) .
首先,我们创建一个Adjacency Matrix代表电话键盘上的合法移动:
我们可以检查矩阵是否对称(不是必需的,但它是系统的属性):
邻接矩阵的输入如下:
A[0,4]=1
表示从顶点0
到顶点4
的移动和A[0,5]=0
表示没有从0
移动到5
.然后我们计算
A
在功率9
处计算,它给出了两个给定顶点之间的长度9
(这对应于长度10
的唯一电话号码的数量)walks的数量(以数字x
开头,以数字y
结尾):路径长度是
n-1
因为顶点是数字而边缘在键盘上移动,因此拨打10
-digits电话号码需要9
移动(行走长度9
) .它给了我们:
Matrix
W
条目读作:W[2,1] = 264
表示264
长度为10
的电话号码,以2
开头,以1
结尾 .现在我们总结从顶点
2
开始的步行:对于您提供的规则集,有
1424
长度为10
的电话号码,以数字2
开头 .功能
这个函数很简单:
该工作的大部分内容包括对Matrix进行编码,该Matrix描述了一组规则(允许在键盘上移动) .
检查
基于观察我们可以从问题描述中得出,比如@SpghttCd,我们可以检查从
2
开始,没有包含数字5
的长度10
的数量:我们可以检查从
5
开始不能写入长度为10
的数字:实际上,对于给定的规则集,数字
5
根本不可用 .我们还可以检查另一个不明显的属性,例如:没有
10
的长度10
,以2
,4
,5
,6
或8
结尾:提示
因为图不是方向的(每个边都存在于两个方向上),所以邻接矩阵是对称的 . 因此矩阵创建可以简化为:
参考文献
一些有用的参考,以了解它的工作原理和原因:
Kenneth H. Rosen ,离散数学及其应用,Mc Graw Hill,第7版,2012年(第688页,计算顶点之间的路径);
http://www-users.math.umn.edu/~musiker/4707/Matrices.pdf
http://www.math.ucsd.edu/~gptesler/184a/slides/184a_ch10.3slides_17-handout.pdf
https://math.dartmouth.edu//archive/m68f11/public_html/algcomb.pdf