老顶级编码器之谜:通过插入 + 来生成数字
我正在考虑这个topcoder问题。
给定一串数字,找到该字符串等于某个目标数字所需的最少加法次数。每次添加都相当于在数字字符串中的某处插入一个加号。插入所有加号后,照常计算总和。
例如,考虑“303”和目标总和为 6。最佳策略是“3+03”。
我会用蛮力解决这个问题,如下:
for each i in 0 to 9 // i -- number of plus signs to insert
for each combination c of i from 10
for each pos in c // we can just split the string w/o inserting plus signs
insert plus sign in position pos
evaluate the expression
if the expression value == given sum
return i
这有意义吗?从性能的角度来看它是否是最佳的?
...
好吧,现在我发现动态编程解决方案会更有效。然而,如果所提出的解决方案有意义的话,那就很有趣了。
I am thinking about this topcoder problem.
Given a string of digits, find the minimum number of additions required for the string to equal some target number. Each addition is the equivalent of inserting a plus sign somewhere into the string of digits. After all plus signs are inserted, evaluate the sum as usual.
For example, consider "303" and a target sum of 6. The best strategy is "3+03".
I would solve it with brute force as follows:
for each i in 0 to 9 // i -- number of plus signs to insert
for each combination c of i from 10
for each pos in c // we can just split the string w/o inserting plus signs
insert plus sign in position pos
evaluate the expression
if the expression value == given sum
return i
Does it make sense? Is it optimal from the performance point of view?
...
Well, now I see that a dynamic programming solution will be more efficient. However it is interesting if the presented solution makes sense anyway.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这当然不是最佳的。例如,如果给定字符串“1234567890”并且目标是三位数,则您知道必须将该字符串拆分为至少四个部分,因此不需要检查 0、1 或 2 次插入。此外,目标还限制了允许插入位置的范围。这两点对于短弦的影响很小,但对于较长的弦可能会产生巨大的影响。不过,我怀疑有一种更好的方法,有点 DP 的味道。
It's certainly not optimal. If, for example, you are given the string "1234567890" and the target is a three-digit number, you know that you have to split the string into at least four parts, so you need not check 0, 1, or 2 inserts. Also, the target limits the range of admissible insertion positions. Both points have small impact for short strings, but can make a huge difference for longer ones. However, I suspect there's a vastly better method, smells a bit of DP.
我还没有考虑太多,但如果你向下滚动,你可以看到比赛的链接,从那里你可以看到求解器的解决方案。这是 C# 中的一个。
I haven't given it much thought yet, but if you scroll down you can see a link to the contest it was from, and from there you can see the solvers' solutions. Here's one in C#.
因为输入长度很小(10),所以所有可能的方式(可以通过长度为10的简单二进制计数器找到)都很小(2^10 = 1024),所以你的算法足够快并返回有效结果,并且IMO有不需要改进它。
总之,直到您的解决方案在时间、内存和其他给定限制下正常工作之前,无需进行微观优化。例如,akappa 提供的这种情况可以用 DP 来解决,就像两部分问题中的 DP 一样,但是当你的算法很快时,就不需要这样做,并且可能会添加一些大常量或使代码不可读。
我只提供一次字符串的解析数字(在长度为 10 的数组中),以防止过多的字符串解析,并且只需使用 a*10^k + ... (您也可以计算 10^k for k=0.. 9 在启动时并保存其值)。
Because input length is small (10) all possible ways (which can be found by a simple binary counter of length 10) is small (2^10 = 1024), so your algorithm is fast enough and returns valid result, and IMO there is no need to improve it.
In all until your solution works fine in time and memory and other given constrains, there is no need to do micro optimization. e.g this case as akappa offered can be solved with DP like DP in two-Partition problem, but when your algorithm is fast there is no need to do this and may be adding some big constant or making code unreadable.
I just offer parse digits of string one time (in array of length 10) to prevent from too many string parsing, and just use a*10^k + ... (Also you can calculate 10^k for k=0..9 in startup and save its value).
我认为这个问题类似于矩阵链乘法问题,我们必须为最小乘法加上大括号。这里的大括号代表“+”。所以我认为它可以通过类似的 dp 方法来解决..将尝试实现它。
I think the problem is similar to Matrix Chain Multiplication problem where we have to put braces for least multiplication. Here braces represent '+'. So I think it could be solved by similar dp approach.. Will try to implement it.
动态规划:
dynamic programming :
似乎为时已晚..但请阅读此处的一些评论和答案,这些评论和答案对 dp 方法说不。但这是一个非常简单的 dp,类似于棒切割问题:
要得到本质:
简单来说,要计算 dp[i][j],您假设最后一个“+”符号的位置 k,然后递归 s[0 ..k]
Seems to be too late .. but just read some comments and answers here which say no to dp approach . But it is a very straightforward dp similar to rod-cutting problem:
To get the essence:
In simple terms , to compute dp[i][j] you assume the position k of last '+' symbol and then recur for s[0..k]