刚刚做的一道原创算法题,题目简单,做起来难,大家看看有什么想法

2018-04-20 21:40:08 +08:00
 lhx2008

输入:n (1 < n < 10^9)

从 1 开始到 n,转成字符串,然后拼接在一起

输出:这个字符串的长度


比如:

输入 13

拼接:12345678910111213

输出 17


特别注意:

时间限制 0.01s 一个数,也就是说不能真的做字符串拼接

2448 次点击
所在节点    问与答
20 条回复
lhx2008
2018-04-20 21:42:04 +08:00
我是花了 40 分钟才做出来,时间复杂度 O(length(n))
njlcazl
2018-04-20 21:45:25 +08:00
看着像数位 dp 的题
orangeade
2018-04-20 21:49:19 +08:00
对每个数按位数分类,然后统计?
orangeade
2018-04-20 21:55:33 +08:00
13:9 * 1 + 4 * 2,
看下 n 的位数,如果是 n=123,就是 9 * 1 + 90 * 2 +(123 - 100 + 1)* 3
找下规律就行
Biggoldfish
2018-04-20 21:57:41 +08:00
今天美团的笔试题吧,就是楼上的思路。AC 代码:
#include <iostream>
#include <cmath>
using namespace std;
int main(){
int T;
cin >> T;
int n = 0, digits = 0;
long long ans = 0;
long long pow10 = 0;
while(T--){
cin >> n;
digits = (int)log10(n);
pow10 = rint(pow(10,digits));
ans = digits * pow10 + (1 - pow10) / 9;
ans += (n - pow10 + 1) * (digits + 1);
cout << ans << endl;
}
return 0;
}
casparchen
2018-04-20 22:00:21 +08:00
有公式啊,O(1)

```
from math import floor, log10
solve = lambda n: (n+1)*floor(log10(10*n)) - (10**floor(log10(10*n))-1)/9
```
tautcony
2018-04-20 22:00:49 +08:00
数数题嘛。设数字为 n,len 为 n 的位数,nine 为 len-1 个 9。ans+=len*(n-nine),然后 n=nine 的,重复操作到只剩个位数就好了。
casparchen
2018-04-20 22:02:52 +08:00
>>>solve(13)
17
>>>solve(123456700)
999999198
ech0x
2018-04-20 22:05:06 +08:00
先将 n 拆分成 n=99....99+m,9 的个数不定,接下去就是数字个数乘以位数 ,这就是个数学问题了。至于位数,我觉得就是这题允许的一个小 trick,转换一个数字到字符串然后获得长度,这个长度就是位数。
lhx2008
2018-04-20 22:09:43 +08:00
@casparchen 这个太强了
lhx2008
2018-04-20 22:11:26 +08:00
@Biggoldfish 是的,是这个搞法
msg7086
2018-04-20 22:29:18 +08:00
放一个简单点的算法:

def solve n
  n = n + 1
  digit = 0
  scale = 1
  while scale < n
   digit += n - scale
   scale *= 10
  end
  digit
end

solve 13
# => 17
solve 123456700
# => 999999198

可能比 log10 大法慢一点,但是都是基本运算,比较容易读。
lhx2008
2018-04-20 22:46:49 +08:00
@msg7086 这个写的也很好,是有公式吗
msg7086
2018-04-20 23:46:25 +08:00
@lhx2008
你这么想,1-9 是一位的,10-99 是两位的,100-999 是三位的。
所以 solve(123) 的位数就是,个位 1~123 十位 10~123 百位 100~123 再相加。

也就是
digit = 0
digit += 123 - 1 + 1
digit += 123 - 10 + 1
digit += 123 - 100 + 1

转写一下就会变成
digit = 0; scale = 1
digit += 123 - scale + 1; scale *= 10
digit += 123 - scale + 1; scale *= 10
digit += 123 - scale + 1; scale *= 10

然后写成循环就好了。
msg7086
2018-04-20 23:53:46 +08:00
这题写成 One liner 也不难的:

def solve n
0.upto(9).map{ |scale| [n + 1 - 10 ** scale, 0].max }.sum
end

solve 123456700
# => 999999198
easylee
2018-04-21 00:55:48 +08:00
希望 V 社区多来些这样的面试算法题,还是挺有趣的。
Bryan0Z
2018-04-21 01:54:57 +08:00
@msg7086 机智,我刚刚看了代码半天没看懂
ericls
2018-04-21 04:53:46 +08:00
这种题有啥意思……
kifile
2018-04-21 07:04:35 +08:00
long number=xxxxxxx;
long length=0;
while(number>0){
length+=number;
number/=10;
}
return length;
pkookp8
2018-04-21 08:31:56 +08:00
既然不用拼接,那就是数学题了。。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/448561

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX