生成系列/返回系列中的第 n 项

Posted

技术标签:

【中文标题】生成系列/返回系列中的第 n 项【英文标题】:generate a Series / return nth term in the series 【发布时间】:2018-05-05 07:29:03 【问题描述】:

我需要生成一个序列,使其成员仅包含 123 数字。例如,1 2 3 11 12 13 21 22 23 31 32 33 111 .... 等等直到 10^18th 术语。 我无法为此推断出任何模式。编写一个代码到系列中的术语数量达到10^18 似乎是不可能的。

1、2、3、11、12、13、21、22、23、31、32、33、111、112、113、121、122、 123、131、132、133、211、212、213、221、222、223、231、232、233、311、 312、313、321、322、323、331、332、333、1111、1112、1113、1121、1122、 1123, 1131, 1132, 1133, 1211, 1212, 1213, 1221 ...

我希望在系列中找到给定的第 n 项。它是一个仅包含123 的数字系统,或者是这些数字的组合,如我们正常的数字系统一样按顺序解释。

【问题讨论】:

序列中有多少个长度为k的项?由此,你能写出一个有效的程序来确定序列中第 n 项的长度吗?如果您做到了这一点,那么您就可以找到完整的解决方案。 是的,对于同样的事情,我推导出了很多术语,但在此之后感到困惑。你能帮我简化一下吗,因为我是编程新手。 因为 N 最多可以达到 10^18 个术语,所以我认为如果我们在提供输入的同时计算它,就竞争性编程而言可能效率不高。 【参考方案1】:

这只是一个以 3 为底的编号系统,只有数字从 1 到 3 而不是从 0 到 2。数学计算方法相同:

1 = 1*3^0 2 = 2*3^0 3 = 3*3^0 4 = 1*3^1 + 1*3^0 5 = 1*3^1 + 2*3^0 6 = 1*3^1 + 3*3^0 7 = 2*3^1 + 1*3^0 ... 19 = 1*3^2 + 3*3^1 + 1*3^0

写两个方法:

    digit(n):计算给定n 的最右边的数字。一些测试用例:digit(4) = 1, digit(5)=2, digit(15)=3。 leftover(n):计算代表 n 但最右边的数字被切掉的数字。一些测试用例:leftover(4) = 1,leftover(15) = 4,leftover(23) = 7。

现在将这两种方法结合到您的问题的解决方案中,该解决方案反复切断最右边的数字,直到没有任何剩余。您可能会发现递归执行此操作更容易。

【讨论】:

【参考方案2】:

你已经提到的序列被称为Numbers that contain only 1's, 2's and 3's。它是由Hieronymus Fischer制定的。

a(n) = sum_j=0..m-1 (1 + b(j) mod 3)*10^j,

where m = floor(log_3(2*n+1)), b(j) = floor((2*n+1-3^m)/(2*3^j)).

您可以在上述链接中查看公式的解释。到目前为止,我已经使用long 编写了它的基本级别。要达到10^18th 术语,您需要使用Java 的BigInteger 类。

class SequenceGeneratorWith123 

    // Written by Soner

    private static double logOfBase(long base, long num) 
        return Math.log(num) / Math.log(base);
    

    private static int mfunc(long n) 
        return (int) Math.floor(logOfBase(3, 2 * n + 1));
    

    private static int b(int j, double m, long n) 
        return (int) Math.floor((2 * n + 1 - Math.pow(3, m)) / (2 * Math.pow(3, j)));
    

    public static void main(String[] args) 

        for (int i = 0; i < 9; i++) 
            long n = (long) Math.pow(10, i);
            int m = mfunc(n);
            long sum = 0;

            for (int j = 0; j < m ; j++) 
                sum += ((1 + b(j, m, n) % 3) * Math.pow(10, j));
            
            System.out.printf("a(10^%d) = %d\n", i, sum);
        

        System.out.println("After the point, overflow will occur " +
                        "because of long type.");    
    

输出:

a(10^0) = 1
a(10^1) = 31
a(10^2) = 3131
a(10^3) = 323231
a(10^4) = 111123331
a(10^5) = 11231311131
a(10^6) = 1212133131231
a(10^7) = 123133223331331
a(10^8) = 13221311111312132
After the point, overflow will occur because of long type.

你只需要玩代码,就是我们只要稍微改变一下main()就可以实现你的愿望。

long n = 1;
// How many terms you need you can alter it by pow() method.
// In this example 10^2 = 100 terms will be obtained.
int term = (int)Math.pow(10, 2);
for (int i = 0; i < term; i++) 

    int m = mfunc(n);
    long sum = 0;

    for (int j = 0; j < m ; j++) 
        sum += ((1 + b(j, m, n) % 3) * Math.pow(10, j));
    
    System.out.printf("%d. term = %d\n", i + 1, sum);
    n++;

输出:

1. term = 1
2. term = 2
3. term = 3
4. term = 11
5. term = 12
6. term = 13
7. term = 21
8. term = 22
9. term = 23
10. term = 31
11. term = 32
12. term = 33
13. term = 111
14. term = 112
15. term = 113
16. term = 121
17. term = 122
18. term = 123
19. term = 131
20. term = 132
21. term = 133
22. term = 211
23. term = 212
24. term = 213
25. term = 221
26. term = 222
27. term = 223
28. term = 231
29. term = 232
30. term = 233
31. term = 311
32. term = 312
33. term = 313
34. term = 321
35. term = 322
36. term = 323
37. term = 331
38. term = 332
39. term = 333
40. term = 1111
41. term = 1112
42. term = 1113
43. term = 1121
44. term = 1122
45. term = 1123
46. term = 1131
47. term = 1132
48. term = 1133
49. term = 1211
50. term = 1212
51. term = 1213
52. term = 1221
53. term = 1222
54. term = 1223
55. term = 1231
56. term = 1232
57. term = 1233
58. term = 1311
59. term = 1312
60. term = 1313
61. term = 1321
62. term = 1322
63. term = 1323
64. term = 1331
65. term = 1332
66. term = 1333
67. term = 2111
68. term = 2112
69. term = 2113
70. term = 2121
71. term = 2122
72. term = 2123
73. term = 2131
74. term = 2132
75. term = 2133
76. term = 2211
77. term = 2212
78. term = 2213
79. term = 2221
80. term = 2222
81. term = 2223
82. term = 2231
83. term = 2232
84. term = 2233
85. term = 2311
86. term = 2312
87. term = 2313
88. term = 2321
89. term = 2322
90. term = 2323
91. term = 2331
92. term = 2332
93. term = 2333
94. term = 3111
95. term = 3112
96. term = 3113
97. term = 3121
98. term = 3122
99. term = 3123
100. term = 3131

【讨论】:

以上是关于生成系列/返回系列中的第 n 项的主要内容,如果未能解决你的问题,请参考以下文章

从 C 中的递归函数中枚举并返回从二维数组中的 n 项中选择 k 的所有组合

仅包含每个重复项中的第一个的 Linq 键

剑指Offer对答如流系列 - 数组中的逆序对

LeetCode系列1185. 一周中的第几天

strtotime 可以在给定日期之后返回一天中的日期和时间吗?

图的最小生成树算法(图解+代码)| 学不会来看我系列