我自己在面试中遇到了这个题目,在面试过程中由于时间关系,自己当时只是描述了一下思路,后来我抽时间把这个思路实现了。这个过程我感觉比较有意思,所以决定分享一下。
开始旋转
暴力求解
这个就很简单了,循环对每个数的每一位上是否有1进行统计,下面是代码。
1 |
|
看看输出结果吧。
12345
start : 1516847188.935077
8121
end : 1516847188.935670
12345678
start : 1516847301.275855
11824417
end : 1516847302.203556
看到最后一个输出时间大概用了一秒钟,WTF!如果我们输入值是9位数,那就很酸爽了,反正我等了大半天没输出结果。
时间复杂度n(log10 n)
二分查找
当我们在把1~n的整数存起来的时候,其实就可以计算其中有多少个1了。不过这里还是可以看一下,从数据存储完成之后的计算需要多少时间。
1 |
|
这个输出结果有点意外哦!
12345
start : 1516866437.180732
8121
end : 1516866437.181642
12345678
start : 1516866444.616205
11824417
end : 1516866445.753807
即使不算存储时间,还是很慢,而且跟预想中的时间复杂度有区别。理论上来说应该比暴力循环快的。
时间复杂度log2 N(N表示1~n的所有整数排列串长度)。
排列组合
由于1~n是连续的整数,也就是说这是一个有规律的排列,那么通过公式来计算肯定会比遍历查询快。
- 假定输入数字长度为l,那么我们计算1个1、2个1…l个1的排列组合情况是不是就可以很高效地得出结果呢?
这里理想情况下每个位置的数是0~9的选择范围,所以在长度小于l的范围适用。
- 那么l长度的排列又怎么处理呢?
设我们输入的数字为653453,在这中六位数的情况下,如果我们把最高位置为1,那么后面的五位数就可以当做一个五位数的全排列来计算,依次累加固定位为2、3、4、5的情况。最高位计算完之后在遍历次高位,再依次累加60、61、62、63、64的情况…以此类推,问题迎刃而解。
1 |
|
晒出我们的输出时间。
12345
start : 1516867095.561999
8121
end : 1516867095.562023
12345678
start : 1516867103.522433
11824417
end : 1516867103.522456
哈哈,输出时间都在20微秒左右,应该算得上是一个比较好的方法吧。
时间复杂度(log10 n)3
提示:评论是disqus,需要使用请翻墙!