题目描述:原题链接
继MIUI8推出手机分身功能之后,MIUI9计划推出一个电话号码分身的功能:首先将电话号码中的每个数字加上8取个位,然后使用对应的大写字母代替 ("ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"), 然后随机打乱这些字母,所生成的字符串即为电话号码对应的分身。
题目分析:
整个过程是从数字到字母的映射过程,题目要求是实现其逆过程,分为两步:
- 从随机打乱的字母转换为数字
- 将中间数字减8还原到原来的数字
- 此外:输出要求是分身前的最小号码,允许0为先导
基本思路:
数字减8的操作很容易实现,即通过字母转换的数字中8-9对应0-1; 0-7对应2-9
对于输出要求最小号码,只需要将数字从小到大排列即可
重点在于从打乱的字母到数字的映射,仔细观察以下特点:
- 某些字母与数字(下文的红色字母)之间有一一映射的关系:'Z' -->0; ''W'-->2; 'X'-->6; 'G'-->8。那么只要有对应的字母存在,就意味着有该数字,且数字出现的次数与字母出现的次数相同
- 通过第一步操作,我们得出了数字0/2/6/8出现的次数,我们可以推算出仅仅与他们有字母交集的其他数字,如’S‘仅存在6和7中,那么7出现的次数就等于'S'出现的次数-6的次数。同理我们可以得到一下几个数字
- ’S‘-6=7
- 'V'-7=5
- 'F'-5=4
- 'H'-8=3
- 最后剩下数字1和9,有公共的字幕N和E,因此,1需要通过’O‘来确定,1 = ’O‘-0-2-4; 9通过字母’I‘来确定,9=’I‘-5-6
ZERO ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT NINE
源代码@Python
1 def deriveNum(str): 2 n = [0 for i in range(10)] 3 n[0] = str.count('Z') 4 n[2] = str.count('W') 5 n[6] = str.count('X') 6 n[8] = str.count('G') 7 n[7] = str.count('S')-n[6] 8 n[5] = str.count('V')-n[7] 9 n[4] = str.count('F')-n[5] 10 n[3] = str.count('H')-n[8] 11 n[1] = str.count('O')-n[0]-n[2]-n[4] 12 n[9] = str.count('I')-n[5]-n[6]-n[8] 13 """ 14 tab = [0 for i in range(26)] 15 for s in str: 16 tab[ord(s)-ord('A')] +=1 17 if tab[ord('Z')-ord('A')]: 18 tmp = tab[ord('Z')-ord('A')] # the number of symbol 0 19 n[0]=tmp 20 tab[ord('Z')-ord('A')] = 0 21 tab[ord('E')-ord('A')] -=tmp 22 tab[ord('R')-ord('A')] -=tmp 23 tab[ord('O')-ord('A')] -=tmp 24 25 if tab[ord('W')-ord('A')]: 26 tmp = tab[ord('W')-ord('A')] # the number of symbol 2 27 n[2]=tmp 28 tab[ord('W')-ord('A')] = 0 29 tab[ord('T')-ord('A')] -=tmp 30 tab[ord('O')-ord('A')] -=tmp 31 32 33 if tab[ord('X')-ord('A')]: 34 tmp = tab[ord('S')-ord('A')] # the number of symbol 6 35 n[6]=tmp 36 tab[ord('X')-ord('A')] = 0 37 tab[ord('S')-ord('A')] -=tmp 38 tab[ord('I')-ord('A')] -=tmp 39 40 if tab[ord('G')-ord('A')]: 41 tmp = tab[ord('G')-ord('A')] # the number of symbol 8 42 n[8]=tmp 43 tab[ord('G')-ord('A')] = 0 44 tab[ord('E')-ord('A')] -=tmp 45 tab[ord('I')-ord('A')] -=tmp 46 tab[ord('H')-ord('A')] -=tmp 47 tab[ord('T')-ord('A')] -=tmp 48 49 if tab[ord('S')-ord('A')]: # S only in 6 and 7 50 tmp = tab[ord('G')-ord('A')] # the number of symbol 7 51 n[7]=tmp 52 tab[ord('S')-ord('A')] = 0 53 tab[ord('E')-ord('A')] -=2*tmp 54 tab[ord('V')-ord('A')] -=tmp 55 tab[ord('N')-ord('A')] -=tmp 56 57 if tab[ord('V')-ord('A')]: #V only for 5 and 7, since 7 has been removed 58 tmp = tab[ord('V')-ord('A')] # the number of symbol 5 59 n[5]=tmp 60 tab[ord('V')-ord('A')] = 0 61 tab[ord('F')-ord('A')] -=tmp 62 tab[ord('I')-ord('A')] -=tmp 63 tab[ord('E')-ord('A')] -=tmp 64 65 if tab[ord('F')-ord('A')]: #V only for 5 and 4, since 5 has been removed 66 tmp = tab[ord('F')-ord('A')] # the number of symbol 4 67 n[4]=tmp 68 tab[ord('F')-ord('A')] = 0 69 tab[ord('I')-ord('A')] -=tmp 70 tab[ord('V')-ord('A')] -=tmp 71 tab[ord('E')-ord('A')] -=tmp 72 73 if tab[ord('I')-ord('A')]: # I only in 5,6,8,9 74 tmp = tab[ord('I')-ord('A')] # the number of 9 75 n[9]=tmp 76 tab[ord('I')-ord('A')] = 0 77 tab[ord('N')-ord('A')] -=2*tmp 78 tab[ord('E')-ord('A')] -=tmp 79 80 if tab[ord('T')-ord('A')]: # I only in 2,3,8 81 tmp = tab[ord('T')-ord('A')] # the number of 3 82 n[3] =tmp 83 tab[ord('T')-ord('A')] = 0 84 tab[ord('H')-ord('A')] -=tmp 85 tab[ord('R')-ord('A')] -=tmp 86 tab[ord('2')-ord('A')] -=2*tmp 87 88 if tab[ord('O')-ord('A')]: 89 tmp = tab[ord('O')-ord('A')] # the number of 1 90 n[1]=tmp 91 tab[ord('O')-ord('A')] = 0 92 tab[ord('N')-ord('A')] -=tmp 93 tab[ord('E')-ord('A')] -=tmp 94 """ 95 return n 96 97 98 99 t = input() 100 for i in range(t): 101 line = raw_input() 102 n1 = deriveNum(line) 103 n = n1[8:10]+n1[0:8] 104 out = '' 105 for i in range(10): 106 out = out+n[i]*str(i) 107 print out
注:
- 用str.count('x')可以直接统计str中字符‘x’出现的次数,从而避免line15-16行通过循环统计次数
- 用包含10个元素的列表来记录数字0-9出现的次数,在第i个位置存储数字i的个数
- 某个字母出现多次时,采用 out = out+n[i]*str(i) 实现多个连续重复字符