A product to do market research, n users to participate in the activities. They give each user a number. The first user number is 1, second users numbered 2, and so on... But no digits 4 and 9 in user's numbers, that is to say the number of 3rd users is 3, the number of 4th users is 5...the number of 8th users is 10... like this:
1 | user 1st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th ........ nth |
简言之,从 \(1\) 开始,将不含 \(4\) 和 \(9\) 的正整数依次写下来,求第 \(n\) 个数。
简单的尝试
暴力穷举,从 \(1\) 开始逐个验证是否含有数码 \(4\) 和 \(9\) 即可。原题仅支持 Javascript 及 C# 代码提交,所以写段 C# :
1 | using System; |
不出所料超时:Process was terminated. It took longer than 12000ms to complete
。
巧用进制
观察符合题意的数字:
1 | 1 2 3 5 6 7 8 |
很容易发现每个数的个位顺序均为 \(0, 1, 2, 3, 5, 6, 7, 8\), 第一行除外。如果将这个序列映射到容易处理的序列如自然数序列、其它进制数序列,则可将问题化归至简单问题上,联想到八进制的逢八进一,把上述列表按照「八进制」的规则重排:
1 | 1 2 3 4 5 6 7 |
建立了一个一一映射 \(\mathrm{II} \mapsto \mathrm{I}\)。于是对于题目中的第 \(n_{(10)}\) 个的数字,可先将其转为八进制后表示的数字 \(n_{(8)}\),在列表 II 中定位这个数,再到列表 I 转换即可。西莎普代码实现:
1 | private static string UserNumber(int n) { |
测试:
1 | 1 : 1 |
拓展 – 包含一系列数字
序列 \(\{c_n\}\) 由正整数中去除含有数字 \(a_1, a_2, \ldots, a_k \ (k < 9, a_i \neq 0)\) 的数组成,确定其第 \(N\) 项。
由于去除了 \(k\) 个数码,所以这个序列中的数字由 \(10 - k\) 个数码组成,这些剩下的数码记为 $ b_1, b_2, , b_{10-k} $。同样的思路,将 \(0, 1, \ldots, 9-k\) 分别对应至 \(b_1, b_2, \ldots, b_{10-k}\),之后将 \(N\) 转为 \(10 - k\) 进制数,利用这层映射关系得到原数。附上 Java 代码:
1 | public static String generalUserNumber(int n, int[] a) { |
测试:
1 | 10 [1, 3, 5, 7, 9] : 40 |