Algorithm 我必须找到第n个数字,它包含数字k或者可以被k整除。(2<;=k<;=9)
示例–如果n=15&k=3,回答:33(3、6、9、12、13、15、18、21、23、24、27、30、31、32、33) 我开始按照顺序来做,但无法表达 对于3->3+3+3+4+3+3+4+3+4+3+3+4+3+3+4的倍数 用于包含数字3-> { 范围在diff=100->1+1+1+10+1+1+1+1+1+1=f(n)说 差异范围=1000-> f(n)+f(n)+f(n)+10*f(n)+f(n)+f(n)+f(n)+f(n)+f(n)+f(n)+f(n)=ff(n)说 差异范围=10000-> ff(n)+ff(n)+ff(n)+10*ff(n)+ff(n)+ff(n)+ff(n)+ff(n)+ff(n)+ff(n)+ff(n)+ff(n)+ff(n) 这一点更进一步 } 我必须用比O(n)或O(1)更好的答案,如果可能的话,请不要建议像检查for循环中的每个数字这样的方法。谢谢Algorithm 我必须找到第n个数字,它包含数字k或者可以被k整除。(2<;=k<;=9),algorithm,math,sequence,Algorithm,Math,Sequence,示例–如果n=15&k=3,回答:33(3、6、9、12、13、15、18、21、23、24、27、30、31、32、33) 我开始按照顺序来做,但无法表达 对于3->3+3+3+4+3+3+4+3+4+3+3+4+3+3+4的倍数 用于包含数字3-> { 范围在diff=100->1+1+1+10+1+1+1+1+1+1=f(n)说 差异范围=1000-> f(n)+f(n)+f(n)+10*f(n)+f(n)+f(n)+f(n)+f(n)+f(n)+f(n)+f(n)=ff(n)说 差异范围
编辑-我到处都搜索过,但在任何地方都找不到答案,因此,它不是重复的。这里有一种方法可以让你思考它,它至少可以指向一个方向(或者,一个白鹅追逐)。将两个问题分开并删除重叠的结果: (1) 有多少个j位数可以被k整除<代码>[j 9/k]-[(j-1)9/k] (2) 有多少个
j位
数字包括数字k
<代码>9*10^(k-1)-8 x 9^(k-1)
现在我们需要减去既可被k
整除的j位
数字,并包括数字k
。但是有多少呢
使用可分性规则来考虑不同的情况。例如:
k = 2
If k is the rightmost digit, any combination of the previous j-1 digits would work.
Otherwise, only combinations with 0,4,6 or 8 as the rightmost digit would work.
k = 5
If k is the rightmost digit, any combination of the previous j-1 digits would work.
Otherwise, only combinations with 0 or 5 as the rightmost digit would work.
etc.
(补遗:我问了关于math.stackexchange的组合问题,得到了一些有趣的答案。这里有一个指向OP关于math.stackexchange的问题的链接:)接下来,如果你有一个O(1)方法来计算d(j,k)
=至少有一位k到j的数字,丢弃可被k整除的数字,然后您可以计算e(j,k)
=至少在数字k上或在j下可被k整除的数字,如j/k+d(j,k)
这允许您使用二进制搜索查找
f(n,k)
,因为k这比我想象的要复杂,但我想我找到了最简单情况(k=2)的解决方案
首先,我试图通过问以下问题来简化:序列中的哪个位置有数字10^I*k
,其中I=1,2,3,…
?对于k=2,数字是20,200,2000
i k n
1 2 20/2 = 10
2 2 200/2 + 2* 5 = 110
3 2 2000/2 + 2* 50 + 18* 5 = 1190
4 2 20000/2 + 2*500 + 18*50 + 162*5 = 12710
i 2 10^i + 2*10^(i-1)/2 + 18*10^(i-2)/2 + 162*10^(i-3)/2 + ?*10^(i-4)/2 + ...
在最后一行中,我试图表达这种模式。第一部分是可除以2的数字。然后是奇数的i-1附加部分,第一个位置为2,第二个位置为2,依此类推。困难的部分是计算系数(2,18,162,…)
这里有一个函数,返回任意i的新因子:
f(i) = 2 * 10^(i-2) - sum(10^(i-x-1)*f(x), x from 2 to i-1) = 2 * 9^(i-2) [thx @m69]
f(2) = 2
f(3) = 2*10 - (1*2) = 18
f(4) = 2*100 - (10*2 + 1*18) = 162
f(5) = 2*1000 - (100*2 + 10*18 + 1*162) = 1458
因此,利用这些信息,我们可以得出以下算法:
找到不超过该位置的最大数字10^i*2
。(如果n
在[positionOf(10^i*2),positionOf(10^i*2)+(10^i)]
范围内,那么我们已经知道解决方案:10^i*2+(n-positionOf(10^i*2))
。例如,如果我们发现i=2,我们知道接下来的100个值都在序列中:[201300],因此如果110 n)
打破
nn+=tmp;
s+=10^ii*2;
}
}
}
返回s;
这是唯一未经测试的未完成伪代码(我知道您不能在Java中使用
^
),ii=1或0需要作为特例处理,此缺失以及如何查找I
也没有显示,否则答案将变得太长 这可以使用二进制搜索+数字dp解决。。。。。
时间复杂度为o(logn*)
有关解决方案,请参见代码:
在此处输入代码
我可以想象O(logn),但对于O(1),您基本上需要找到一个公式f(n,k)=解决方案或不解决方案?建议我O(logn)。。谢谢。@maraca肯定对解决这个问题非常感兴趣,不仅仅是简单的循环。不管怎么说,数字的数量都必须是log_10(n),因为每10个数字中至少有1个是k,但如果小于log_10(n)-1个数字,你根本就没有n个数字。事实上,它是ceil(log_10(n))或ceil(log_10(n))+1。现在去读吉拉德的答案:)这个答案看起来不错。为了计算出重叠的结果,可以使用基于DP[x][y]=包含特殊数字的x位数(其值等于特殊数字的y模)以及DP2[x][y]的动态规划=不包含值等于y mod special digit的特殊数字的x位数。@PeterDrivaz感谢您的评论。我必须考虑一下你建议的DB定义,看看我是否理解。你们能提供一个有效的实现吗?我看不出一种方法可以轻易地得到第n个数字。谢谢。@rishavbansal一种方法可能是:一旦你确定了第n个n
数字的位数,修复最左边的数字,然后向右移动——比如,如果最左边的数字是1
,使用组合学和可分性规则计算了多少特殊数字?如果是2
?等等。当你找到合适的最左边的数字时,转到它右边的下一个数字,依此类推。@rishavbansal这里也看到了,为什么3和9的组合/整除选项不是很重要呢?我不知道如何使用7:)那么,有多少数字6可以被3整除,比如说5000?一件事是存在一个整除性规则(也有一个用于7),另一件事是使用该规则在不循环j次的情况下得到d(j,k)。给你:2,18,162,1458…=2*(9^0,9^1,9^2,9^3…)良好的观察+1。现在我把答案保持原样,因为它显示了我是如何得出这些数字的,也许它可以以某种方式推广到任何k。我已经从这个链接上我的问题的答案中推导出了一个解决方案,似乎效果很好。
int nn = positionOf(10^i * 2);
int s = 10^i * 2;
for (int ii = i; ii >= 0; ii--) {
for (int j = 1; j < 10; j++) {
if (j == 1 || j == 6) {
if (n <= nn + 10^ii)
return s + nn - n;
nn += 10^ii;
s += 10^ii;
int tmp = positionOf(10^ii);
if (nn + tmp > n)
break;
nn += tmp;
s += 10^ii;
} else {
int tmp = positionOf(10^ii * 2);
if (nn + tmp > n)
break;
nn += tmp;
s += 10^ii * 2;
}
}
}
return s;