今天有一个高中的同学在网上问了我一到ACM的题,是关于找selfnumbers数的,要求运行时间至少要是O(nlog(n)),空间要比O(n)要小。
立马我就上wikipedia网查一下,关于selfnumbers的定义和有关数学的解法(没办法啊,咱数学功底还没那么厚,只能站在巨人的肩膀上,^_^)。O(∩_∩)O哈哈~,wikipedia还真伟大啊,还真有。我摘抄了一部分:(http://en.wikipedia.org/wiki/Self_number)
Reduction tests
Luke Pebody showed (Oct 2006) that a link can be made between the self property of a large number n and a low-order portion of that number, adjusted for digit sums:
a) In general, n is self if and only if m = R(n)+SOD(R(n))-SOD(n) is self
Where:
R(n) is the smallest rightmost digits of n, greater than 9.d(n)
d(n) is the number of digits in n
SOD(x) is the sum of digits of x, the function S10(x) from above.
b) If n = a.10^b+c, c<10^b, then n is self if and only if both {m1 & m2} are negative or self
Where:
m1 = c - SOD(a)
m2 = SOD(a-1)+9.b-(c+1)
c) For the simple case of a=1 & c=0 in the previous model (i.e. n=10^b), then n is self if and only if (9.b-1) is self
SOD(n) is the sum of all digits in n
d(n) is the number of digits in n
哈哈,看到了没,b方案就是我们要找的数学解决方案。下面是我刚开始写的解决方案:
看一下Solve函数里的双层循环,就知道它的运行时间是O(n^3),差太多了。函数的运行时间都耗在这里了。看来不行啊。行,把他修改一下,知道两个循环都是为了求r中是否有m1,m2的存在,没必要要花费双层循环来解决这个问题啊。行,要找m1和m2吗。R中数字是排序号的,那可以用二分查找啊。下面是我的简单实现:
来测试一下,(图1是第一的实现(查找10000以内的selfnumbers),图2是第二次的实现(查找1000000以内的self))。
图一
图二
看到了差距了吧。来分析一下他的时间,这里主要就时间就花在二分查找里,他的时间是O(nlog(n));而空间是O(n),经过我测试空间可以是n/10.(n要比较大)。
行了。就写到这里了,如果朋友您有更好的解决方案,欢迎来找我讨论。我将非常高兴。