鱼C论坛

 找回密码
 立即注册
查看: 4876|回复: 35

[技术交流] Python: 每日一题 36

[复制链接]
发表于 2017-5-2 23:03:45 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 ooxx7788 于 2017-5-3 18:31 编辑

# ┌───┬───┬───┐
# │ 1 │ 2 │ 3 │
# ├───┼───┼───┤
# │ 4 │ 5 │ 6 │
# ├───┼───┼───┤
# │ 7 │ 8 │ 9 │
# └───┼───┼───┘
#       │ 0 │
#      └───┘

好了,警探,我们的一个同事成功地观察到了我们的目标人,Robby the抢劫犯。我们跟着他来到一个秘密仓库,在那里我们假设能找到所有偷来的东西。这个仓库的门是由一个电子组合锁锁闭的(键盘如上图)。不幸的是,我们的间谍不确定他看到当罗比进入它的时候那个PIN。

他指出,PIN 1357,但他也说,他看到的每一个数字可能实际上是另一个相邻的数字(水平或垂直,但不是对角)。
例如1,它也可以是2或4。
例如5,它也可以是2、4、6或8。

他也提到过,他知道这种锁。你可以输入无限数量的错误的,它们永远不会锁定系统或发出警报。这就是为什么我们可以尝试所有可能的变化。
观察到的可能是PIN本身和所有的变化考虑相邻的数字
你能帮我们找出这些变化吗?如果有一个函数,它会返回一个所有变量的数组,其长度为1到8位。我们可以命名函数getPINs(python中的get_pins)。但是请注意,所有的PIN,观察到的和结果,都必须是字符串,因为有可能以“0”开头。我们已经为您准备了一些测试用例。
警探,我们指望你了!

OK,今天的题目还有点RPG色彩!不知道题意是否明确了,这是经过翻译软件后,我稍微整理的内容。最关键的部分我已经用红字标出。

同样的,下面我给出测试代码,test.py请参见本专辑33,34题中。
  1. expectations = [('8', ['5','7','8','9','0']),
  2.                 ('11',["11", "22", "44", "12", "21", "14", "41", "24", "42"]),
  3.                 ('369', ["339","366","399","658","636","258","268","669","668","266","369","398","256","296","259","368","638","396","238","356","659","639","666","359","336","299","338","696","269","358","656","698","699","298","236","239"])]

  4. for tup in expectations:
  5.   test.assert_equals(sorted(get_pins(tup[0])), sorted(tup[1]), 'PIN: ' + tup[0])
复制代码



最后,是我写的一个不太简便,但是比较通用的答案。
游客,如果您要查看本帖隐藏内容请回复

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-5-3 11:50:35 | 显示全部楼层
不是很明白你的问题,仅针对你的题目PIN为“1357”时,输出所有可能的密码组合:
  1. import itertools
  2. dic = {'1': ['1', '2', '4'], '2': ['1', '2', '3', '5'], '3': ['2', '3', '6'], '4': ['1', '4', '5', '7'], '5': ['2', '4', '5', '6', '8'], '6': ['3', '5', '6', '9'], '7': ['4', '7', '8'], '8': ['5', '7', '8', '9', '0'], '9': ['6', '8', '9'], '0': ['0', '8']}

  3. def get_pins(pins):
  4.     mainlist = []
  5.     for pin in str(pins):
  6.         mainlist.append(dic[pin])
  7.     comb = itertools.product(mainlist[0], mainlist[1], mainlist[2], mainlist[3])
  8.     for c in comb:
  9.         yield ''.join(c)
  10. for pin in get_pins(1357):
  11.     print(pin)
复制代码

输出:
1224
1227
1228
1244
1247
1248
1254
1257
1258
1264
1267
1268
1284
1287
1288
1324
1327
1328
1344
1347
1348
1354
1357
1358
1364
1367
1368
1384
1387
1388
1624
1627
1628
1644
1647
1648
1654
1657
1658
1664
1667
1668
1684
1687
1688
2224
2227
2228
2244
2247
2248
2254
2257
2258
2264
2267
2268
2284
2287
2288
2324
2327
2328
2344
2347
2348
2354
2357
2358
2364
2367
2368
2384
2387
2388
2624
2627
2628
2644
2647
2648
2654
2657
2658
2664
2667
2668
2684
2687
2688
4224
4227
4228
4244
4247
4248
4254
4257
4258
4264
4267
4268
4284
4287
4288
4324
4327
4328
4344
4347
4348
4354
4357
4358
4364
4367
4368
4384
4387
4388
4624
4627
4628
4644
4647
4648
4654
4657
4658
4664
4667
4668
4684
4687
4688

***Repl Closed***
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-5-3 11:55:57 | 显示全部楼层
jerryxjr1220 发表于 2017-5-3 11:50
不是很明白你的问题,仅针对你的题目PIN为“1357”时,输出所有可能的密码组合:

输出:

没错,就是这个意思。
其实就是两步,一步是查询pin中每一个数字对应的可能组合。
第二步,就是把所有组合进行排列组合。
对于第一步而言,使用字典确实是不错的方法。但是如果换一个更大的键盘,比如字母键盘,相对来说建立字典会费事一些。
对于第二步而言,product方法确实省事。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 14:04:33 | 显示全部楼层
看看答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 18:10:18 | 显示全部楼层
  1. # coding=utf-8
  2. PIN='1357'
  3. dict={}
  4. for i in PIN:#制造一个包含PIN本身和相邻数字的字典dict
  5.     dict[i]=[]
  6.     if i==8:
  7.         dict[i].append('0')
  8.     top,left,right,bottom=int(i)-3,int(i)-1,int(i)+1,int(i)+3
  9.     if top>0:
  10.         dict[i].append(top)
  11.     if left>0:
  12.         dict[i].append(left)
  13.     dict[i].append(i)
  14.     if right<=9:
  15.         dict[i].append(right)
  16.     if bottom<=9:
  17.         dict[i].append(bottom)
  18.         
  19. #排列组合
  20. for first in dict['1']:
  21.     for second in dict['3']:
  22.         for third in dict['5']:
  23.             for fourth in dict['7']:
  24.                 print '%s%s%s%s'%(first,second,third,fourth)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 18:25:17 | 显示全部楼层
  1. #2.7
  2. a = {1:list('123'),2:list('456'),3:list('789'),4:list('n0n')}
  3. s = {}
  4. test = '586'
  5. c = 0
  6. for k in list(test):
  7.     for i in a:
  8.         r = []
  9.         if k in a[i]:
  10.             
  11.             b = a[i].index(k)
  12.             if i-1 >= 1:
  13.                  r.append(a[i-1][b])
  14.             if i+1 <= 4:
  15.                  r.append(a[i+1][b])
  16.             if b-1 >= 0:
  17.                  r.append(a[i][b-1])
  18.             if b+1 <= 2:
  19.                  r.append(a[i][b+1])
  20.             r.append(a[i][b])
  21.             r = [j for j in r if j !='n']
  22.             s[c] = r
  23.             c+=1
  24. #这部分是抄袭楼主的
  25. def foo(x, y):
  26.     temp = []
  27.     for i in x:
  28.         for j in y:
  29.             temp.append(i + j)
  30.     return temp


  31. print list(reduce(foo, [s[i] for i in range(len(s))]))
  32.                            
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-5-3 18:26:14 | 显示全部楼层

你的这个答案好像局限性很大啊,只是针对1357这一个PIN组合。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 18:32:06 | 显示全部楼层
位数是1到8位,我一个个列还能列的出来,如果再多的话我这样就明细显得很累赘了,不知道怎么把任意位写成一条
  1. zd={'0':['0','8'],'1':['1','2','4'],'2':['1','2','3','5'],'3':['2','3','6'],'4':['1','4','5','7'],'5':['2','4','5','6','8'],'6':['3','5','6','9'],'7':['4','7','8'],'8':['5','7','8','9','0'],'9':['6','8','9']}
  2. def get_pins(p):
  3.     pp=list(p)
  4.     pl=len(pp)
  5.     if   pl==1:pin=zd[pp[0]]
  6.     elif pl==2:pin=[x1+x2 for x1 in zd[pp[0]] for x2 in zd[pp[1]]]
  7.     elif pl==3:pin=[x1+x2+x3 for x1 in zd[pp[0]] for x2 in zd[pp[1]] for x3 in zd[pp[2]]]
  8.     elif pl==4:pin=[x1+x2+x3+x4 for x1 in zd[pp[0]] for x2 in zd[pp[1]] for x3 in zd[pp[2]] for x4 in zd[pp[3]]]
  9.     elif pl==5:pin=[x1+x2+x3+x4+x5 for x1 in zd[pp[0]] for x2 in zd[pp[1]] for x3 in zd[pp[2]] for x4 in zd[pp[3]] for x5 in zd[pp[4]]]
  10.     elif pl==6:pin=[x1+x2+x3+x4+x5+x6 for x1 in zd[pp[0]] for x2 in zd[pp[1]] for x3 in zd[pp[2]] for x4 in zd[pp[3]] for x5 in zd[pp[4]] for x6 in zd[pp[5]]]
  11.     elif pl==7:pin=[x1+x2+x3+x4+x5+x6+x7 for x1 in zd[pp[0]] for x2 in zd[pp[1]] for x3 in zd[pp[2]] for x4 in zd[pp[3]] for x5 in zd[pp[4]] for x6 in zd[pp[5]] for x7 in zd[pp[6]]]
  12.     elif pl==8:pin=[x1+x2+x3+x4+x5+x6+x7+x8 for x1 in zd[pp[0]] for x2 in zd[pp[1]] for x3 in zd[pp[2]] for x4 in zd[pp[3]] for x5 in zd[pp[4]] for x6 in zd[pp[5]] for x7 in zd[pp[6]] for x8 in zd[pp[7]]]     
  13.     return pin
  14. print(get_pins('1357'))
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-5-3 18:32:33 | 显示全部楼层

reduce在这里其实用jerry的product确实是更好的,就不需要自定义一个函数了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 18:39:03 | 显示全部楼层
刚开始看了jerryxjr1220的代码,发现itertools库的pruduce函数,也想用这个,可是用的时候发现随着test长度的变化,必须要改变produce里的参数的数目,感觉不够灵活(可能自己水平不够),看了下楼主的发现了reduce函数。请问下按照pruduce函数能灵活的做出这题吗
  1. import itertools
  2. a = {1:list('123'),2:list('456'),3:list('789'),4:list('n0n')}
  3. s = {}
  4. test = '369'
  5. c = 0
  6. for k in list(test):
  7.     for i in a:
  8.         r = []
  9.         if k in a[i]:
  10.             
  11.             b = a[i].index(k)
  12.             if i-1 >= 1:
  13.                  r.append(a[i-1][b])
  14.             if i+1 <= 4:
  15.                  r.append(a[i+1][b])
  16.             if b-1 >= 0:
  17.                  r.append(a[i][b-1])
  18.             if b+1 <= 2:
  19.                  r.append(a[i][b+1])
  20.             r.append(a[i][b])
  21.             r = [j for j in r if j !='n']
  22.             s[c] = r
  23.             c+=1

  24. print list(itertools.product([s[i] for i in range(len(s))]))


  25. #返回itertools.product([mainlist[0], mainlist[1], mainlist[2]])



  26. #  由于列表推导式返回的是列表,而不是
  27. #  itertools.product(mainlist[0], mainlist[1], mainlist[2])
  28. #  这样的,所以有什么办法吗
  29.    
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 18:43:16 | 显示全部楼层
ooxx7788 发表于 2017-5-3 18:32
reduce在这里其实用jerry的product确实是更好的,就不需要自定义一个函数了。

我也想过的,当test的长度为四时comb = itertools.product(mainlist[0], mainlist[1], mainlist[2], mainlist[3])
为3时comb = itertools.product(mainlist[0], mainlist[1], mainlist[2)要改变长度,所以想到列表推导式,可是也遇到了问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 18:52:02 | 显示全部楼层
ooxx7788 发表于 2017-5-3 18:26
你的这个答案好像局限性很大啊,只是针对1357这一个PIN组合。

# coding=utf-8
def get_pins(observe):
    dict={}
    result=[]
    for i in observe:#制造一个包含PIN本身和相邻数字的字典dict
        dict=[]
        if i=='8':
            dict.append('0')
        top,left,right,bottom=int(i)-3,int(i)-1,int(i)+1,int(i)+3
        if top>0:
            dict.append(top)
        if left>0:
            dict.append(left)
        dict.append(i)
        if right<=9:
            dict.append(right)
        if bottom<=9:
            dict.append(bottom)

        
#排列组合
    for first in dict[observe[0]]:
        for second in dict[observe[1]]:
            for third in dict[observe[2]]:
                for fourth in dict[observe[3]]:
                    result.append('%s%s%s%s'%(first,second,third,fourth))
    return result
print get_pins('2468')

这样可以吗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-5-3 19:51:13 | 显示全部楼层
余欲渔 发表于 2017-5-3 18:32
位数是1到8位,我一个个列还能列的出来,如果再多的话我这样就明细显得很累赘了,不知道怎么把任意位写成一 ...

大神,你这写的是什么啊?你这样我要是给的是个10个数字组成的,求总的可能组合的数量,你这写法要爆炸了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-5-3 19:52:08 | 显示全部楼层
18813034116 发表于 2017-5-3 18:52
# coding=utf-8
def get_pins(observe):
    dict={}

如果我给的是5位数的字符串呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-5-3 19:53:32 | 显示全部楼层
小锟 发表于 2017-5-3 18:39
刚开始看了jerryxjr1220的代码,发现itertools库的pruduce函数,也想用这个,可是用的时候发现随着test长度 ...

看答案,里面我更新了。
当然不是我写的,因为我开始把product给忘记了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 20:48:32 | 显示全部楼层
ooxx7788 发表于 2017-5-3 19:51
大神,你这写的是什么啊?你这样我要是给的是个10个数字组成的,求总的可能组合的数量,你这写法要爆炸了 ...

还是不熟悉啊,我也想写成一条,尝试了几个写法,返回来的都不对,join也用了。看了你简洁版的知道该怎么写了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-3 20:56:30 | 显示全部楼层
ooxx7788 发表于 2017-5-3 19:51
大神,你这写的是什么啊?你这样我要是给的是个10个数字组成的,求总的可能组合的数量,你这写法要爆炸了 ...

修改了一下,应该就是product后面用*来代表任意位数
  1. import itertools
  2. zd={'0':['0','8'],'1':['1','2','4'],'2':['1','2','3','5'],'3':['2','3','6'],'4':['1','4','5','7'],'5':['2','4','5','6','8'],'6':['3','5','6','9'],'7':['4','7','8'],'8':['5','7','8','9','0'],'9':['6','8','9']}
  3. def get_pins(p):
  4.     pin=[''.join(p) for p in itertools.product(*(zd[i] for i in p))]
  5.     return pin
  6. print(get_pins('1357'))
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-4 16:14:47 | 显示全部楼层
jerryxjr1220 发表于 2017-5-3 11:50
不是很明白你的问题,仅针对你的题目PIN为“1357”时,输出所有可能的密码组合:

输出:

方法想的跟你这个一样,也是先建立一个字典,然后获取一个元素是列表的列表,再把元素中的数字迭代组合成字符串
但是有个问题一直没有想到办法,那就是密码的长度变化问题,你这个只是针对密码长度是4的,换成其他长度就不行,并不是通用,我就卡在这个地方了,因为不知道获取的列表中有多少个元素,不知道怎么去循环
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-4 18:01:33 From FishC Mobile | 显示全部楼层
gopythoner 发表于 2017-5-4 16:14
方法想的跟你这个一样,也是先建立一个字典,然后获取一个元素是列表的列表,再把元素中的数字迭代组合成 ...

我是针对这个题目所以这样写的,长度不定可以用*号,解答里面已经写了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-4 21:09:58 | 显示全部楼层
ooxx7788 发表于 2017-5-3 19:52
如果我给的是5位数的字符串呢?
  1. # coding=utf-8
  2. def get_pins(observe):
  3.     dict={}
  4.     result=[]
  5.     for i in observe:#制造一个包含PIN本身和相邻数字的字典dict
  6.         dict[i]=[]
  7.         if i=='8':
  8.             dict[i].append('0')
  9.         top,left,right,bottom=str(int(i)-3),str(int(i)-1),str(int(i)+1),str(int(i)+3)
  10.         if int(top)>0:
  11.             dict[i].append(top)
  12.         if int(left)>0 and int(left)%3!=0:
  13.             dict[i].append(left)
  14.         dict[i].append(i)
  15.         if int(right)<=9 and int(i) % 3!=0:
  16.             dict[i].append(right)
  17.         if int(bottom)<=9:
  18.             dict[i].append(bottom)
  19.     print dict
  20.    
  21. #排列组合
  22.     list_temp=[]
  23.     list_result=['']
  24.     n=len(observe)-1
  25.     while True:
  26.         for i in dict[observe[n]]:
  27.             for j in list_result:
  28.                 list_temp.append(i+j)
  29.         n-=1
  30.         list_result=list_temp
  31.         list_temp=[]
  32.         if n<0:
  33.             break
  34.     return list_result        

复制代码

重新看了下发现我的代码还是有不少问题,这是修改后可以输入任意长度字符的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-28 16:34

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表